{
  "openapi": "3.1.0",
  "info": {
    "title": "Develosaur agent gateway",
    "version": "1.6.95",
    "description": "Read and write develosaur project boards - a visual graph where humans and AI agents plan together. Call getCookbook FIRST: it is the one instruction document, and everything these operations expect of you is defined there.\n\nNO ACCOUNT NEEDED: createSandbox returns a throwaway board and a bearer token; send the token on every other call, and ALWAYS give the user the board_url / view_url that comes back.\n\nClients that speak the Model Context Protocol should prefer https://mcp.develosaur.com/v1/mcp instead - it exposes a richer tool set.",
    "contact": {
      "url": "https://develosaur.com"
    }
  },
  "servers": [
    {
      "url": "https://mcp.develosaur.com",
      "description": "Develosaur agent gateway"
    }
  ],
  "security": [
    {
      "sandboxToken": []
    }
  ],
  "components": {
    "securitySchemes": {
      "sandboxToken": {
        "type": "http",
        "scheme": "bearer",
        "description": "The sandbox_token returned by POST /v1/sandbox."
      }
    }
  },
  "paths": {
    "/llms.txt": {
      "get": {
        "operationId": "getCookbook",
        "summary": "The develosaur cookbook - read this before writing anything",
        "description": "The complete instruction document for agents: how to connect, the autonomy rules, the work loop, and the plan/work/sync chapters. Call this FIRST if you have not read it; everything the other operations expect of you is defined here.",
        "security": [],
        "responses": {
          "200": {
            "description": "The cookbook, as plain-text markdown.",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/v1/sandbox": {
      "post": {
        "operationId": "createSandbox",
        "summary": "Start a free anonymous sandbox project",
        "description": "START HERE if you have no credentials. Returns sandbox_token - send it as \"Authorization: Bearer <sandbox_token>\" on every other call. Also returns view_url: share that link with the user IMMEDIATELY so they can watch the board build in real time. Sandboxes are throwaway: server memory only, evicted after 60 minutes idle, capped at 500 nodes and 8MB.",
        "security": [],
        "responses": {
          "201": {
            "description": "Sandbox created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "sandbox_token": {
                      "type": "string",
                      "description": "Bearer token for all subsequent calls."
                    },
                    "project_id": {
                      "type": "string"
                    },
                    "view_url": {
                      "type": "string",
                      "description": "Human link to the live board. Share this with the user."
                    },
                    "mcp_url": {
                      "type": "string",
                      "description": "Equivalent MCP endpoint, if the client speaks MCP."
                    },
                    "expires_at": {
                      "type": "string",
                      "format": "date-time"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Per-address mint limit or global capacity reached."
          }
        }
      }
    },
    "/v1/health": {
      "get": {
        "operationId": "getHealth",
        "summary": "Gateway liveness and version",
        "security": [],
        "responses": {
          "200": {
            "description": "Gateway is up.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "version": {
                      "type": "string"
                    },
                    "uptime_s": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded."
          }
        }
      }
    },
    "/v1/sandbox/{token}/claim": {
      "post": {
        "operationId": "claimSandbox",
        "summary": "Convert a live sandbox into a permanent project in the user account",
        "description": "Requires an OAuth (dsat_) bearer obtained via the device flow - see /llms.txt, \"Working on the user's REAL boards\". Copies the sandbox board (nodes, edges, tags) into a new project owned by the authorized user, then retires the sandbox. Offer this when the user says \"keep this board\" after authorizing. Sandbox bearers cannot call it.",
        "parameters": [
          {
            "name": "token",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "Project name. Defaults to the board root title."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "project_id": {
                      "type": "string"
                    },
                    "name": {
                      "type": "string"
                    },
                    "nodes_saved": {
                      "type": "integer"
                    },
                    "edges_saved": {
                      "type": "integer"
                    },
                    "board_url": {
                      "type": "string",
                      "description": "The claimed project in the develosaur app. Share it with the user."
                    },
                    "note": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer token."
          },
          "429": {
            "description": "Rate limit exceeded."
          }
        }
      }
    },
    "/v1/projects": {
      "post": {
        "operationId": "createProject",
        "summary": "Create a new empty project board in the user account",
        "description": "Requires an authorized bearer: an OAuth (dsat_) token from the device flow, or the local host token on a desktop install. Creates a real, permanent board with a single root node named after the project. Anonymous sandbox bearers are refused - mint a sandbox (POST /v1/sandbox) to build without an account, or claim an existing sandbox (POST /v1/sandbox/{token}/claim) once the user has authorized you.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "name"
                ],
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Project name. Also the title of the root node."
                  },
                  "description": {
                    "type": "string",
                    "description": "Optional one-line description."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "project_id": {
                      "type": "string"
                    },
                    "name": {
                      "type": "string"
                    },
                    "board_url": {
                      "type": "string",
                      "description": "The new project in the develosaur app. Share it with the user."
                    },
                    "note": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer token."
          },
          "429": {
            "description": "Rate limit exceeded."
          }
        }
      }
    },
    "/v1/projects/{projectId}/tree": {
      "get": {
        "operationId": "getTree",
        "summary": "Read the whole board as an indented outline",
        "description": "Call this FIRST in every session: it shows the structure and returns board_url, the link to share with the user. Cheap - titles and ids only, no node content.",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id. Pass the literal string 'default' - in an anonymous sandbox every id resolves to your own sandbox project, and 'default' is the value the mint response and the tree endpoint both hand you.",
            "schema": {
              "type": "string",
              "default": "default"
            }
          },
          {
            "name": "max_depth",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "description": "Limit tree depth."
          },
          {
            "name": "include_completed",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "Include completed nodes (default false)."
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "project_id": {
                      "type": "string"
                    },
                    "tree": {
                      "type": "string",
                      "description": "Indented text outline: title, id, tags, scores."
                    },
                    "board_url": {
                      "type": "string",
                      "description": "Link where the user can SEE this board. Share it with them."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer token."
          },
          "429": {
            "description": "Rate limit exceeded."
          }
        }
      }
    },
    "/v1/projects/{projectId}/nodes": {
      "get": {
        "operationId": "findNodes",
        "summary": "Search nodes by exact text match",
        "description": "Case-insensitive substring match on title or content. Use before creating anything, to extend an existing node instead of duplicating it.",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id. Pass the literal string 'default' - in an anonymous sandbox every id resolves to your own sandbox project, and 'default' is the value the mint response and the tree endpoint both hand you.",
            "schema": {
              "type": "string",
              "default": "default"
            }
          },
          {
            "name": "q",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Substring to match."
          },
          {
            "name": "tag",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "TODO",
                "BUG",
                "CRITICAL",
                "VALIDATE",
                "IN-PROGRESS",
                "COMPLETED"
              ]
            }
          },
          {
            "name": "completed",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "project_id": {
                      "type": "string"
                    },
                    "count": {
                      "type": "integer"
                    },
                    "nodes": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer token."
          },
          "429": {
            "description": "Rate limit exceeded."
          }
        }
      },
      "post": {
        "operationId": "createNodes",
        "summary": "Create one node, or many at once",
        "description": "Pass the nodes array whenever you are creating more than one node - each entry carries temp_id plus one placement (parent_id, parent_temp_id, or is_rogue), so a whole branch lands atomically with its parent-child links intact. For exactly one node you may instead pass title + parent_id at the top level and omit nodes. Bodies are plain UTF-8 markdown: never base64-encode content, and never put a whole document into one node - split it into a tree. Responses carry board_url - the link where the user can SEE this board. Share it with the user.",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id. Pass the literal string 'default' - in an anonymous sandbox every id resolves to your own sandbox project, and 'default' is the value the mint response and the tree endpoint both hand you.",
            "schema": {
              "type": "string",
              "default": "default"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "nodes": {
                    "type": "array",
                    "description": "The batch shape - PREFERRED whenever creating more than one node. Omit only for a single top-level node.",
                    "items": {
                      "type": "object",
                      "required": [
                        "temp_id",
                        "title"
                      ],
                      "properties": {
                        "temp_id": {
                          "type": "string",
                          "description": "Local id so other entries in this batch can reference it as a parent."
                        },
                        "parent_id": {
                          "type": "string",
                          "description": "Existing node id to attach under."
                        },
                        "parent_temp_id": {
                          "type": "string",
                          "description": "temp_id of another node in THIS batch."
                        },
                        "is_rogue": {
                          "type": "boolean"
                        },
                        "title": {
                          "type": "string",
                          "description": "Node title. Plain ASCII, no emojis, no em-dashes."
                        },
                        "content_markdown": {
                          "type": "string",
                          "description": "Markdown body of the node."
                        },
                        "type": {
                          "type": "string",
                          "enum": [
                            "tasks",
                            "richtext",
                            "deadline"
                          ],
                          "default": "tasks"
                        },
                        "color": {
                          "type": "string",
                          "description": "Hex color, e.g. '#4299e1'."
                        },
                        "tags": {
                          "type": "array",
                          "items": {
                            "type": "string",
                            "enum": [
                              "TODO",
                              "BUG",
                              "CRITICAL",
                              "VALIDATE",
                              "IN-PROGRESS",
                              "COMPLETED"
                            ]
                          },
                          "description": "Sandbox projects have a fixed tag set; other values are rejected."
                        },
                        "v_score": {
                          "type": "number",
                          "minimum": 0,
                          "maximum": 10,
                          "description": "Business value 0-10."
                        },
                        "e_score": {
                          "type": "number",
                          "minimum": 0,
                          "maximum": 10,
                          "description": "Effort estimate 0-10."
                        },
                        "deadline": {
                          "type": "string",
                          "description": "Due date, YYYY-MM-DD."
                        },
                        "blocked_by": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          },
                          "description": "Node ids blocking this one."
                        },
                        "position": {
                          "type": "integer",
                          "minimum": 0,
                          "description": "0-based display order among the parent's children; omit to append. The tree outline, hid addresses, and the TODO derivation all follow it. Out-of-range values clamp."
                        }
                      }
                    }
                  },
                  "parent_id": {
                    "type": "string",
                    "description": "Single-node form: existing parent node id. Required unless is_rogue."
                  },
                  "is_rogue": {
                    "type": "boolean",
                    "description": "Single-node form: create an unparented free-floating node."
                  },
                  "title": {
                    "type": "string",
                    "description": "Node title. Plain ASCII, no emojis, no em-dashes."
                  },
                  "content_markdown": {
                    "type": "string",
                    "description": "Markdown body of the node."
                  },
                  "type": {
                    "type": "string",
                    "enum": [
                      "tasks",
                      "richtext",
                      "deadline"
                    ],
                    "default": "tasks"
                  },
                  "color": {
                    "type": "string",
                    "description": "Hex color, e.g. '#4299e1'."
                  },
                  "tags": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": [
                        "TODO",
                        "BUG",
                        "CRITICAL",
                        "VALIDATE",
                        "IN-PROGRESS",
                        "COMPLETED"
                      ]
                    },
                    "description": "Sandbox projects have a fixed tag set; other values are rejected."
                  },
                  "v_score": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 10,
                    "description": "Business value 0-10."
                  },
                  "e_score": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 10,
                    "description": "Effort estimate 0-10."
                  },
                  "deadline": {
                    "type": "string",
                    "description": "Due date, YYYY-MM-DD."
                  },
                  "blocked_by": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Node ids blocking this one."
                  },
                  "position": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "0-based display order among the parent's children; omit to append. The tree outline, hid addresses, and the TODO derivation all follow it. Out-of-range values clamp."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "node_id": {
                      "type": "string"
                    },
                    "created": {
                      "type": "integer"
                    },
                    "id_mapping": {
                      "type": "object",
                      "description": "temp_id -> real node id, for batch creates."
                    },
                    "board_url": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer token."
          },
          "429": {
            "description": "Rate limit exceeded."
          }
        }
      }
    },
    "/v1/projects/{projectId}/nodes/{nodeId}": {
      "get": {
        "operationId": "getNode",
        "summary": "Read one node in full",
        "description": "Full content, tags, scores, parent, children, and blockers for a single node.",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id. Pass the literal string 'default' - in an anonymous sandbox every id resolves to your own sandbox project, and 'default' is the value the mint response and the tree endpoint both hand you.",
            "schema": {
              "type": "string",
              "default": "default"
            }
          },
          {
            "name": "nodeId",
            "in": "path",
            "required": true,
            "description": "Node id (uuid) as returned by the tree or a create call.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer token."
          },
          "429": {
            "description": "Rate limit exceeded."
          }
        }
      },
      "patch": {
        "operationId": "updateNode",
        "summary": "Update a node",
        "description": "Only the fields you pass are changed. Responses carry board_url - the link where the user can SEE this board. Share it with the user.",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id. Pass the literal string 'default' - in an anonymous sandbox every id resolves to your own sandbox project, and 'default' is the value the mint response and the tree endpoint both hand you.",
            "schema": {
              "type": "string",
              "default": "default"
            }
          },
          {
            "name": "nodeId",
            "in": "path",
            "required": true,
            "description": "Node id (uuid) as returned by the tree or a create call.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "title": {
                    "type": "string",
                    "description": "Node title. Plain ASCII, no emojis, no em-dashes."
                  },
                  "content_markdown": {
                    "type": "string",
                    "description": "Markdown body of the node."
                  },
                  "type": {
                    "type": "string",
                    "enum": [
                      "tasks",
                      "richtext",
                      "deadline"
                    ],
                    "default": "tasks"
                  },
                  "color": {
                    "type": "string",
                    "description": "Hex color, e.g. '#4299e1'."
                  },
                  "tags": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": [
                        "TODO",
                        "BUG",
                        "CRITICAL",
                        "VALIDATE",
                        "IN-PROGRESS",
                        "COMPLETED"
                      ]
                    },
                    "description": "Sandbox projects have a fixed tag set; other values are rejected."
                  },
                  "v_score": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 10,
                    "description": "Business value 0-10."
                  },
                  "e_score": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 10,
                    "description": "Effort estimate 0-10."
                  },
                  "deadline": {
                    "type": "string",
                    "description": "Due date, YYYY-MM-DD."
                  },
                  "blocked_by": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Node ids blocking this one."
                  },
                  "position": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "0-based display order among this node's CURRENT siblings - a reposition within the existing parent (use the move route to change parents). Sibling order, not TODO rank."
                  },
                  "exclude_from_priority": {
                    "type": "boolean",
                    "description": "Opt the node out of the TODO list entirely (true) or back in (false). It stays on the canvas and in the tree; it just never appears in the list, whatever its tags say. Setting true also unpins it."
                  },
                  "manual_priority": {
                    "type": "integer",
                    "description": "Ordinal in the pinned head: 1 = top. Prefer the pin/unpin/reorder routes, which maintain contiguity."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "node_id": {
                      "type": "string"
                    },
                    "board_url": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer token."
          },
          "429": {
            "description": "Rate limit exceeded."
          }
        }
      },
      "delete": {
        "operationId": "deleteNode",
        "summary": "Delete a node, optionally with its subtree",
        "description": "Call with dry_run=true FIRST to see what would be removed. Deleting a node with children requires confirm_cascade=true.",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id. Pass the literal string 'default' - in an anonymous sandbox every id resolves to your own sandbox project, and 'default' is the value the mint response and the tree endpoint both hand you.",
            "schema": {
              "type": "string",
              "default": "default"
            }
          },
          {
            "name": "nodeId",
            "in": "path",
            "required": true,
            "description": "Node id (uuid) as returned by the tree or a create call.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "dry_run",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "Preview only; deletes nothing."
          },
          {
            "name": "confirm_cascade",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "Required to delete a node that has children."
          },
          {
            "name": "max_cascade",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "description": "Refuse if the cascade exceeds this many nodes."
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer token."
          },
          "429": {
            "description": "Rate limit exceeded."
          }
        }
      }
    },
    "/v1/projects/{projectId}/grow": {
      "post": {
        "operationId": "growBoard",
        "summary": "Grow a whole branch from a markdown outline in one call",
        "description": "THE PREFERRED WAY to create more than a couple of nodes. Write a plain markdown outline: headings become nodes (# depth = tree depth, levels are relative), every other line becomes the content of the heading above it, every heading becomes a node. No JSON tree to assemble, no temp ids, no size tricks - the outline IS the payload. Responses carry board_url - the link where the user can SEE this board. Share it with the user.",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id. Pass the literal string 'default' - in an anonymous sandbox every id resolves to your own sandbox project, and 'default' is the value the mint response and the tree endpoint both hand you.",
            "schema": {
              "type": "string",
              "default": "default"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "outline"
                ],
                "properties": {
                  "outline": {
                    "type": "string",
                    "description": "The markdown outline. Example: \"# Trip\\nTwo weeks.\\n## Flights\\nCompare carriers.\\n## Budget\\n~2000 total.\" creates three nested nodes."
                  },
                  "parent_id": {
                    "type": "string",
                    "description": "Existing node to grow the branch under. Omit to grow under the project root."
                  },
                  "tags": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": [
                        "TODO",
                        "BUG",
                        "CRITICAL",
                        "VALIDATE",
                        "IN-PROGRESS",
                        "COMPLETED"
                      ]
                    },
                    "description": "Applied to every LEAF of the new branch (untagged nodes never appear in the TODO list)."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "created": {
                      "type": "integer"
                    },
                    "leaves": {
                      "type": "integer"
                    },
                    "nodes": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "title": {
                            "type": "string"
                          }
                        }
                      }
                    },
                    "board_url": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer token."
          },
          "429": {
            "description": "Rate limit exceeded."
          }
        }
      }
    },
    "/v1/projects/{projectId}/nodes/{nodeId}/complete": {
      "post": {
        "operationId": "completeNode",
        "summary": "Mark a node completed",
        "description": "Clears its tags, adds COMPLETED, and stamps the completion time. Responses carry board_url - the link where the user can SEE this board. Share it with the user.",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id. Pass the literal string 'default' - in an anonymous sandbox every id resolves to your own sandbox project, and 'default' is the value the mint response and the tree endpoint both hand you.",
            "schema": {
              "type": "string",
              "default": "default"
            }
          },
          {
            "name": "nodeId",
            "in": "path",
            "required": true,
            "description": "Node id (uuid) as returned by the tree or a create call.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "node_id": {
                      "type": "string"
                    },
                    "completed": {
                      "type": "boolean"
                    },
                    "board_url": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer token."
          },
          "429": {
            "description": "Rate limit exceeded."
          }
        }
      }
    },
    "/v1/projects/{projectId}/edges": {
      "post": {
        "operationId": "createEdge",
        "summary": "Link an existing node under a parent",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id. Pass the literal string 'default' - in an anonymous sandbox every id resolves to your own sandbox project, and 'default' is the value the mint response and the tree endpoint both hand you.",
            "schema": {
              "type": "string",
              "default": "default"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "parent_id",
                  "child_id"
                ],
                "properties": {
                  "parent_id": {
                    "type": "string"
                  },
                  "child_id": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "board_url": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer token."
          },
          "429": {
            "description": "Rate limit exceeded."
          }
        }
      }
    },
    "/v1/projects/{projectId}/nodes/{nodeId}/move": {
      "post": {
        "operationId": "moveNode",
        "summary": "Re-parent a node",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id. Pass the literal string 'default' - in an anonymous sandbox every id resolves to your own sandbox project, and 'default' is the value the mint response and the tree endpoint both hand you.",
            "schema": {
              "type": "string",
              "default": "default"
            }
          },
          {
            "name": "nodeId",
            "in": "path",
            "required": true,
            "description": "Node id (uuid) as returned by the tree or a create call.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "new_parent_id"
                ],
                "properties": {
                  "new_parent_id": {
                    "type": "string"
                  },
                  "mode": {
                    "type": "string",
                    "enum": [
                      "subtree",
                      "node_only"
                    ],
                    "default": "subtree",
                    "description": "subtree moves descendants too."
                  },
                  "position": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "0-based display order among the NEW parent's children; omit to append."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "node_id": {
                      "type": "string"
                    },
                    "board_url": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer token."
          },
          "429": {
            "description": "Rate limit exceeded."
          }
        }
      }
    },
    "/v1/projects/{projectId}/capture": {
      "post": {
        "operationId": "captureNote",
        "summary": "Drop a quick unfiled note onto the board",
        "description": "For a thought that has no home yet. Creates an unparented node; file it later with moveNode.",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id. Pass the literal string 'default' - in an anonymous sandbox every id resolves to your own sandbox project, and 'default' is the value the mint response and the tree endpoint both hand you.",
            "schema": {
              "type": "string",
              "default": "default"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "text": {
                    "type": "string",
                    "description": "Note body. The first line becomes the title if none is given."
                  },
                  "title": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "node_id": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer token."
          },
          "429": {
            "description": "Rate limit exceeded."
          }
        }
      }
    },
    "/v1/projects/{projectId}/priority": {
      "get": {
        "operationId": "getPriorityOrder",
        "summary": "Ranked TODO order for the board",
        "description": "Three layers, reported per entry as source: overdue first (hard constraint), then the manually pinned head in manual_priority order, then everything else in depth-first tree order. A blocked node never sorts above its blocker. Returns the FULL report - this route has no compact mode.",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id. Pass the literal string 'default' - in an anonymous sandbox every id resolves to your own sandbox project, and 'default' is the value the mint response and the tree endpoint both hand you.",
            "schema": {
              "type": "string",
              "default": "default"
            }
          },
          {
            "name": "actionable_only",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "Only nodes with a deadline or any tag (tagged = in the pipeline; default true)."
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "under_parent_id",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Restrict to one subtree."
          },
          {
            "name": "tag",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Restrict to nodes carrying this tag id. Filtering preserves relative order, so a tag lens reads as its own 1..N list."
          },
          {
            "name": "sprint_length_days",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "description": "Default 14. Converts e_score into effort_days."
          },
          {
            "name": "include_future",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "Default true. False drops nodes whose work window has not opened yet."
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "entries": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "node_id": {
                            "type": "string"
                          },
                          "rank": {
                            "type": "integer",
                            "description": "1-based position across the whole list."
                          },
                          "manual_priority": {
                            "type": "integer",
                            "nullable": true,
                            "description": "Head ordinal, or null when not pinned."
                          },
                          "source": {
                            "type": "string",
                            "enum": [
                              "doing",
                              "overdue",
                              "pinned",
                              "derived"
                            ],
                            "description": "Which layer placed this entry."
                          },
                          "held_by": {
                            "type": "string",
                            "nullable": true,
                            "description": "Agent holding a live lease on this task, or null."
                          },
                          "lease_until": {
                            "type": "string",
                            "nullable": true,
                            "description": "ISO expiry of the live lease."
                          },
                          "abandoned_by": {
                            "type": "string",
                            "nullable": true,
                            "description": "Holder whose lease expired without a release: a quiet or crashed agent."
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer token."
          },
          "429": {
            "description": "Rate limit exceeded."
          }
        }
      }
    },
    "/v1/projects/{projectId}/priority/frontier": {
      "get": {
        "operationId": "getFrontier",
        "summary": "The ready set a worker may take right now",
        "description": "The frontier, not the ordered list: pipeline entries inside their work window with every blocker resolved, not IN-PROGRESS, and (unless include_containers) with no unresolved children. Same ranking pass as getPriorityOrder, but rows carry an order inside the set and no global rank. The scope parameters are applied on top of readiness (frontier THEN filter), so a scoped read never returns a node blocked by work outside the scope. An empty frontier carries a starvation reason (cycle, nothing_tagged, all_blocked, all_held, undecomposed, window_closed); blocker cycles among unresolved nodes are always named.",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id. Pass the literal string 'default' - in an anonymous sandbox every id resolves to your own sandbox project, and 'default' is the value the mint response and the tree endpoint both hand you.",
            "schema": {
              "type": "string",
              "default": "default"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "description": "Rows returned (default 20). width always reports the full ready-set size."
          },
          {
            "name": "under_parent_id",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Restrict to one subtree (a worker branch lens)."
          },
          {
            "name": "tag",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Restrict to nodes carrying this tag id (a worker tag lens)."
          },
          {
            "name": "include_containers",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "Default false. True also lists ready nodes that still have unresolved children."
          },
          {
            "name": "sprint_length_days",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "description": "Default 14. Converts e_score into effort_days."
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "frontier": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "order": {
                            "type": "integer",
                            "description": "1-based position inside the frontier. Not a global rank."
                          },
                          "node_id": {
                            "type": "string"
                          },
                          "title": {
                            "type": "string"
                          },
                          "tags": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          },
                          "effort_days": {
                            "type": "number"
                          },
                          "source": {
                            "type": "string",
                            "enum": [
                              "doing",
                              "overdue",
                              "pinned",
                              "derived"
                            ]
                          },
                          "unblocks": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            },
                            "description": "Unresolved node ids that move closer to ready when this completes."
                          }
                        }
                      }
                    },
                    "width": {
                      "type": "integer",
                      "description": "Size of the ready set before limit."
                    },
                    "considered": {
                      "type": "integer",
                      "description": "Pipeline entries in scope the frontier was computed over."
                    },
                    "pool": {
                      "type": "object",
                      "description": "Live lease holders across the whole board.",
                      "properties": {
                        "active_workers": {
                          "type": "integer"
                        },
                        "holders": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "agent": {
                                "type": "string"
                              },
                              "holding": {
                                "type": "integer"
                              },
                              "next_expiry": {
                                "type": "string"
                              }
                            }
                          }
                        }
                      }
                    },
                    "starving": {
                      "type": "boolean",
                      "description": "The ready set is narrower than the active pool: decompose."
                    },
                    "excluded": {
                      "type": "object",
                      "properties": {
                        "blocked": {
                          "type": "integer"
                        },
                        "held": {
                          "type": "integer"
                        },
                        "containers": {
                          "type": "integer"
                        },
                        "window_closed": {
                          "type": "integer"
                        }
                      }
                    },
                    "cycles": {
                      "type": "array",
                      "description": "Blocker cycles among unresolved nodes, each as the ordered member list.",
                      "items": {
                        "type": "object",
                        "properties": {
                          "nodes": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "properties": {
                                "node_id": {
                                  "type": "string"
                                },
                                "title": {
                                  "type": "string"
                                }
                              }
                            }
                          }
                        }
                      }
                    },
                    "starvation": {
                      "type": "object",
                      "nullable": true,
                      "properties": {
                        "reason": {
                          "type": "string",
                          "enum": [
                            "cycle",
                            "nothing_tagged",
                            "all_blocked",
                            "all_held",
                            "undecomposed",
                            "window_closed"
                          ]
                        },
                        "detail": {
                          "type": "string"
                        },
                        "unblock_first": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "node_id": {
                                "type": "string"
                              },
                              "title": {
                                "type": "string"
                              },
                              "holds_back": {
                                "type": "integer"
                              }
                            }
                          }
                        }
                      }
                    },
                    "board_url": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer token."
          },
          "429": {
            "description": "Rate limit exceeded."
          }
        }
      }
    },
    "/v1/projects/{projectId}/priority/reorder": {
      "post": {
        "operationId": "reorderPriority",
        "summary": "Rewrite the pinned head of the TODO list",
        "description": "ordered_ids becomes the ENTIRE pinned head, written as contiguous manual_priority 1..N in one atomic change. Ids not previously pinned become pinned; previously pinned ids omitted from the list are unpinned and fall back to their derived tree position. Non-actionable ids are rejected.",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id. Pass the literal string 'default' - in an anonymous sandbox every id resolves to your own sandbox project, and 'default' is the value the mint response and the tree endpoint both hand you.",
            "schema": {
              "type": "string",
              "default": "default"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "ordered_ids"
                ],
                "properties": {
                  "ordered_ids": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Node ids in the desired head order (1-50)."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "head": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "node_id": {
                            "type": "string"
                          },
                          "manual_priority": {
                            "type": "integer"
                          }
                        }
                      }
                    },
                    "unpinned": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "board_url": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer token."
          },
          "429": {
            "description": "Rate limit exceeded."
          }
        }
      }
    },
    "/v1/projects/{projectId}/nodes/{nodeId}/pin": {
      "post": {
        "operationId": "pinNode",
        "summary": "Pin a node into the priority head",
        "description": "Inserts the node at a 1-based head position, shifting the rest down and keeping the head contiguous. Omit position to append. Re-pinning an already-pinned node moves it. Rejects non-actionable nodes.",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id. Pass the literal string 'default' - in an anonymous sandbox every id resolves to your own sandbox project, and 'default' is the value the mint response and the tree endpoint both hand you.",
            "schema": {
              "type": "string",
              "default": "default"
            }
          },
          {
            "name": "nodeId",
            "in": "path",
            "required": true,
            "description": "Node id (uuid) as returned by the tree or a create call.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "position": {
                    "type": "integer",
                    "minimum": 1,
                    "description": "1-based head position. Omit to append."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "head": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "node_id": {
                            "type": "string"
                          },
                          "manual_priority": {
                            "type": "integer"
                          }
                        }
                      }
                    },
                    "board_url": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer token."
          },
          "429": {
            "description": "Rate limit exceeded."
          }
        }
      }
    },
    "/v1/projects/{projectId}/nodes/{nodeId}/archive": {
      "post": {
        "operationId": "archiveNode",
        "summary": "Archive a node and its descendants (recoverable)",
        "description": "Sets a branch aside as if deleted, but recoverably: it stops rendering on the canvas and never enters the TODO list, while the node and its edges survive so unarchive restores it exactly where it was, including sibling order. CASCADES TO DESCENDANTS - send dry_run first to see the size. The project root cannot be archived.",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id. Pass the literal string 'default' - in an anonymous sandbox every id resolves to your own sandbox project, and 'default' is the value the mint response and the tree endpoint both hand you.",
            "schema": {
              "type": "string",
              "default": "default"
            }
          },
          {
            "name": "nodeId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "dry_run": {
                    "type": "boolean",
                    "description": "Preview only: report what WOULD change and change nothing. Archiving cascades to every descendant, so call this first on anything you did not create yourself."
                  },
                  "max_cascade": {
                    "type": "integer",
                    "description": "Refuse if the cascade would touch more than this many nodes."
                  },
                  "confirm_cascade": {
                    "type": "boolean",
                    "description": "Required acknowledgement when the cascade is large."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "changed": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      },
                      "description": "Node ids actually changed (empty on a dry run)."
                    },
                    "considered": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      },
                      "description": "Every node the cascade covers."
                    },
                    "archived": {
                      "type": "boolean"
                    },
                    "dryRun": {
                      "type": "boolean",
                      "description": "Echoes whether this was a preview. Check it."
                    },
                    "board_url": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer token."
          },
          "429": {
            "description": "Rate limit exceeded."
          }
        }
      }
    },
    "/v1/projects/{projectId}/nodes/{nodeId}/unarchive": {
      "post": {
        "operationId": "unarchiveNode",
        "summary": "Restore an archived node and its descendants",
        "description": "Reverses archiveNode. The branch returns to the canvas and the TODO derivation in its original position. Cascades the same way; dry_run is supported.",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id. Pass the literal string 'default' - in an anonymous sandbox every id resolves to your own sandbox project, and 'default' is the value the mint response and the tree endpoint both hand you.",
            "schema": {
              "type": "string",
              "default": "default"
            }
          },
          {
            "name": "nodeId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "dry_run": {
                    "type": "boolean",
                    "description": "Preview only: report what WOULD change and change nothing. Archiving cascades to every descendant, so call this first on anything you did not create yourself."
                  },
                  "max_cascade": {
                    "type": "integer",
                    "description": "Refuse if the cascade would touch more than this many nodes."
                  },
                  "confirm_cascade": {
                    "type": "boolean",
                    "description": "Required acknowledgement when the cascade is large."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "changed": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      },
                      "description": "Node ids actually changed (empty on a dry run)."
                    },
                    "considered": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      },
                      "description": "Every node the cascade covers."
                    },
                    "archived": {
                      "type": "boolean"
                    },
                    "dryRun": {
                      "type": "boolean",
                      "description": "Echoes whether this was a preview. Check it."
                    },
                    "board_url": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer token."
          },
          "429": {
            "description": "Rate limit exceeded."
          }
        }
      }
    },
    "/v1/projects/{projectId}/nodes/{nodeId}/unpin": {
      "post": {
        "operationId": "unpinNode",
        "summary": "Remove a node from the priority head",
        "description": "Closes the ordinal gap so the head keeps reading 1..N. The node falls back to its derived tree position rather than disappearing. Completing a node unpins it automatically.",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id. Pass the literal string 'default' - in an anonymous sandbox every id resolves to your own sandbox project, and 'default' is the value the mint response and the tree endpoint both hand you.",
            "schema": {
              "type": "string",
              "default": "default"
            }
          },
          {
            "name": "nodeId",
            "in": "path",
            "required": true,
            "description": "Node id (uuid) as returned by the tree or a create call.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "head": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "node_id": {
                            "type": "string"
                          },
                          "manual_priority": {
                            "type": "integer"
                          }
                        }
                      }
                    },
                    "unpinned": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "board_url": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer token."
          },
          "429": {
            "description": "Rate limit exceeded."
          }
        }
      }
    },
    "/v1/projects/{projectId}/priority/start": {
      "post": {
        "operationId": "startWork",
        "summary": "Start work on nodes: tag IN-PROGRESS, pin, and CLAIM them",
        "description": "The one call that begins work. Tags each node IN-PROGRESS, pins them in the order given (the DOING layer), and leases each one to the caller for 45 minutes. A node held by a LIVE lease of another agent refuses the whole call with 409 naming the holder and expiry; pass takeover:true only when you know the holder is gone. Any write by the holder renews the lease; completion, archive, clearing IN-PROGRESS, release, or handoff ends it; expiry ends it silently. Identity: body.agent, else the X-Develosaur-Agent header, else the host session.",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id. Pass the literal string 'default' - in an anonymous sandbox every id resolves to your own sandbox project, and 'default' is the value the mint response and the tree endpoint both hand you.",
            "schema": {
              "type": "string",
              "default": "default"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "node_ids"
                ],
                "properties": {
                  "node_ids": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Nodes to start, in DOING order."
                  },
                  "position": {
                    "type": "integer",
                    "minimum": 1,
                    "description": "Where the DOING run begins in the head (default 1)."
                  },
                  "agent": {
                    "type": "string",
                    "maxLength": 120,
                    "description": "A stable name for this session; the lease is held under it."
                  },
                  "takeover": {
                    "type": "boolean",
                    "description": "Displace a live lease held by someone else. Default false."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "changed": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "nodeId": {
                            "type": "string"
                          },
                          "title": {
                            "type": "string"
                          }
                        }
                      }
                    },
                    "unchanged": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "nodeId": {
                            "type": "string"
                          },
                          "title": {
                            "type": "string"
                          }
                        }
                      }
                    },
                    "head": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "node_id": {
                            "type": "string"
                          },
                          "manual_priority": {
                            "type": "integer"
                          }
                        }
                      }
                    },
                    "leases": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "node_id": {
                            "type": "string"
                          },
                          "title": {
                            "type": "string"
                          },
                          "held_by": {
                            "type": "string"
                          },
                          "lease_until": {
                            "type": "string",
                            "description": "ISO expiry."
                          },
                          "taken_over_from": {
                            "type": "string",
                            "description": "Previous holder, when takeover displaced a live lease."
                          }
                        }
                      }
                    },
                    "board_url": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer token."
          },
          "429": {
            "description": "Rate limit exceeded."
          }
        }
      }
    },
    "/v1/projects/{projectId}/priority/release": {
      "post": {
        "operationId": "releaseLeases",
        "summary": "Put down every task the caller holds",
        "description": "Clears every lease held under the caller identity (body.agent, else the X-Develosaur-Agent header, else the host session). IN-PROGRESS tags are left alone: the work still shows as started, and the frontier shows it as takeable. handoff does this for you at session end.",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id. Pass the literal string 'default' - in an anonymous sandbox every id resolves to your own sandbox project, and 'default' is the value the mint response and the tree endpoint both hand you.",
            "schema": {
              "type": "string",
              "default": "default"
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "agent": {
                    "type": "string",
                    "maxLength": 120
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "agent": {
                      "type": "string"
                    },
                    "released": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "node_id": {
                            "type": "string"
                          },
                          "title": {
                            "type": "string"
                          }
                        }
                      }
                    },
                    "board_url": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer token."
          },
          "429": {
            "description": "Rate limit exceeded."
          }
        }
      }
    }
  }
}