{
  "schema": "nlo.agent-tools.v0",
  "status": "preview: not switched on at neverlogoff.com yet",
  "note": "Page builder tools for a person's own AI. Same format as agents/tools.json. Every tool sends or receives the ONE page JSON (schemas/nlo-page-v0.json) — exactly what the browser editor at /me/page uses. ask_human_first = get the human's yes for this exact call. A save that makes a block public which was not public before answers 409 needs_confirm {blocks}: ask the human, then repeat the call with confirm_public: true.",
  "base_url": "https://neverlogoff.com",
  "auth_kinds": {
    "none": "no sign-in",
    "cookie": "the human's sign-in cookie, only in their browser",
    "page_token": "Authorization: Bearer nlou1.… with typ nlo-page-push. The human makes it at /me/page (\"Make a key for my AI\"); 60 minutes; reads and changes THIS person's page only. It cannot upload posts or site files."
  },
  "tools": [
    {
      "name": "get_page",
      "description": "Read the human's page: the full page JSON (custom HTML inline), its address and the current version number.",
      "inputSchema": { "type": "object", "additionalProperties": false, "properties": {} },
      "annotations": { "readOnlyHint": true },
      "x_nlo": { "method": "GET", "path": "/api/page?op=get", "auth": "page_token", "ask_human_first": false, "status": "preview" }
    },
    {
      "name": "put_page",
      "description": "REPLACE the whole page with a new version (the last 10 are kept; undo puts one back). Call get_page first, change its page, and send its ver as base_version: without it, or if the page changed since, the answer is 409 stale_page {current_version} and nothing is saved (a first page needs none). To change one block, prefer add_block, move_block or set_block_visibility. Validated server-side: unknown block types or keys are refused.",
      "inputSchema": { "type": "object", "additionalProperties": false, "required": ["page"], "properties": { "page": { "$ref": "/schemas/nlo-page-v0.json" }, "base_version": { "type": "integer", "minimum": 1, "description": "the ver from get_page (or the header If-Match: \"<ver>\"); required once the person has a page" }, "confirm_public": { "type": "boolean", "description": "only after the human said yes to the blocks named in needs_confirm" } } },
      "annotations": { "readOnlyHint": false, "destructiveHint": false },
      "x_nlo": { "method": "POST", "path": "/api/page?op=put", "auth": "page_token", "ask_human_first": true, "status": "preview", "needs_confirm": "409 {error:'needs_confirm', blocks:[ids]} when a block that was private or hidden would become public", "stale_page": "409 {error:'stale_page', current_version} when base_version is missing or not the newest version" }
    },
    {
      "name": "list_blocks",
      "description": "The block types you can use, each with its default settings and whether the sharing tools may make a card for it, plus the wall's sources, views, formats and limits.",
      "inputSchema": { "type": "object", "additionalProperties": false, "properties": {} },
      "annotations": { "readOnlyHint": true },
      "x_nlo": { "method": "GET", "path": "/api/page?op=blocks", "auth": "none", "ask_human_first": false, "status": "preview" }
    },
    {
      "name": "add_block",
      "description": "Add one block and save. The server picks the id (stable, never reused on this page) and returns it with its anchor #b-<id>. at = position (0 = top); default the end.",
      "inputSchema": { "type": "object", "additionalProperties": false, "required": ["type"], "properties": { "type": { "enum": ["wall", "about", "links", "post", "stream", "clips", "coin", "custom", "ask_ai"] }, "settings": { "type": "object" }, "visibility": { "enum": ["public", "followers", "approved", "only_me"] }, "at": { "type": "integer", "minimum": 0 }, "confirm_public": { "type": "boolean" } } },
      "annotations": { "readOnlyHint": false },
      "x_nlo": { "method": "POST", "path": "/api/page?op=add-block", "auth": "page_token", "ask_human_first": true, "status": "preview" }
    },
    {
      "name": "move_block",
      "description": "Move a block to a position (to, 0 = top) or one step (dir up/down), and save.",
      "inputSchema": { "type": "object", "additionalProperties": false, "required": ["id"], "properties": { "id": { "type": "string", "pattern": "^[a-z0-9]{2,12}$" }, "to": { "type": "integer", "minimum": 0 }, "dir": { "enum": ["up", "down"] } } },
      "annotations": { "readOnlyHint": false },
      "x_nlo": { "method": "POST", "path": "/api/page?op=move-block", "auth": "page_token", "ask_human_first": false, "status": "preview" }
    },
    {
      "name": "set_block_visibility",
      "description": "Change who sees one block (public, followers, approved, only_me) and/or hide it, and save. Making a private or hidden block public needs the human's yes: the first call answers needs_confirm.",
      "inputSchema": { "type": "object", "additionalProperties": false, "required": ["id"], "properties": { "id": { "type": "string", "pattern": "^[a-z0-9]{2,12}$" }, "visibility": { "enum": ["public", "followers", "approved", "only_me"] }, "hidden": { "type": "boolean" }, "confirm_public": { "type": "boolean" } } },
      "annotations": { "readOnlyHint": false },
      "x_nlo": { "method": "POST", "path": "/api/page?op=set-visibility", "auth": "page_token", "ask_human_first": true, "status": "preview" }
    },
    {
      "name": "search_posts",
      "description": "Search posts (to pick a post for a post block, or to try a wall's saved search). Words resolve to places and topics and expand down the hierarchy (england finds Manchester). Newest first. Without a sign-in you see public posts only.",
      "inputSchema": { "type": "object", "additionalProperties": false, "properties": { "q": { "type": "string", "maxLength": 300 }, "format": { "type": "string" }, "name": { "type": "string" }, "from": { "type": "string" }, "to": { "type": "string" }, "limit": { "type": "integer", "maximum": 200 } } },
      "annotations": { "readOnlyHint": true },
      "x_nlo": { "method": "GET", "path": "/api/posts?op=search", "auth": "none", "ask_human_first": false, "status": "preview" }
    },
    {
      "name": "preview_url",
      "description": "A link (10 minutes) to the saved page — or the editor's draft if there is one — as a signed-out visitor sees it. Hand it to the human before asking them to confirm.",
      "inputSchema": { "type": "object", "additionalProperties": false, "properties": {} },
      "annotations": { "readOnlyHint": true },
      "x_nlo": { "method": "GET", "path": "/api/page?op=preview-url", "auth": "page_token", "ask_human_first": false, "status": "preview" }
    },
    {
      "name": "undo_page",
      "description": "Put back the previous version (or ver = one of the last 10) as a new version.",
      "inputSchema": { "type": "object", "additionalProperties": false, "properties": { "ver": { "type": "integer", "minimum": 1 }, "confirm_public": { "type": "boolean" } } },
      "annotations": { "readOnlyHint": false },
      "x_nlo": { "method": "POST", "path": "/api/page?op=undo", "auth": "page_token", "ask_human_first": true, "status": "preview" }
    },
    {
      "name": "list_page_versions",
      "description": "The last 10 saved versions, newest first, with each block's id, type and visibility.",
      "inputSchema": { "type": "object", "additionalProperties": false, "properties": {} },
      "annotations": { "readOnlyHint": true },
      "x_nlo": { "method": "GET", "path": "/api/page?op=versions", "auth": "page_token", "ask_human_first": false, "status": "preview" }
    }
  ]
}
