{
  "schema": "context-mcp-catalog/1",
  "server": {
    "key": "context",
    "name": "Context",
    "endpoint": "https://mcp.onecontext.me/mcp",
    "purpose": "Context is the shared workspace for your goals and how agents execute them across every host you use. The Shared Space works the moment you sign in with Google; pairing your iPhone in the Context app unlocks Private Spaces and the Personal domains — memories, logs, people, health, calendar and skills — that live only on your phone.",
    "auth": {
      "type": "oauth2",
      "scopes": [
        "context:shared",
        "context:private"
      ],
      "signIn": "Google",
      "stepUp": "Pair your iPhone in the Context app, then Reconnect the connector"
    },
    "contractVersion": "3.0.0",
    "startingPrompt": "Nomi, get me started",
    "generatedAt": "2026-09-05T13:01:53.231Z",
    "sourceRepo": "asaubhagya/meetly-macos",
    "sourcePath": "supabase/functions/mcp/tools_v3.ts",
    "sourceCommit": "2a5d1c0e"
  },
  "connect": {
    "claude-ai": "Settings → Connectors → Add custom connector → name Context, URL https://mcp.onecontext.me/mcp → Connect",
    "chatgpt": "Settings → Connectors → Add → URL https://mcp.onecontext.me/mcp",
    "claude-code": "claude mcp add --transport http context https://mcp.onecontext.me/mcp",
    "cursor": "Add an HTTP MCP server with URL https://mcp.onecontext.me/mcp"
  },
  "skills": [
    {
      "key": "context",
      "role": "base",
      "description": "The interface — how you talk to Context: primitives, vocabulary, and when to call which tool."
    },
    {
      "key": "rules",
      "role": "harness",
      "description": "Execution discipline — how a work unit runs end to end, from plan through verification to handoff."
    },
    {
      "key": "setup-context",
      "role": "harness",
      "description": "Chart a map — turns a goal into an Epic, its Issues and a spec before any work starts."
    },
    {
      "key": "daily-brief",
      "role": "harness",
      "description": "Daily heartbeat — a recurring digest of what changed and what needs the user's attention."
    },
    {
      "key": "wayfinder",
      "role": "third-party",
      "description": "Planning method (third-party) — structures how a hard decision or plan gets explored."
    },
    {
      "key": "grill-me",
      "role": "third-party",
      "description": "Planning method (third-party) — stress-tests a plan or idea by grilling it round by round."
    }
  ],
  "toolGroups": [
    {
      "key": "start",
      "title": "Start",
      "access": "shared",
      "tools": [
        {
          "name": "start_context",
          "title": "Start a Context session",
          "description": "Use this when you need to orient yourself in Context before doing anything else — at the top of a session, whenever you are unsure which tool fits, or when the user greets Nomi or says \"Nomi, get me started\". Read-only: it reports the signed-in account, whether an iPhone is paired, which Spaces and modules you can reach, the guide and `context` skill Resources (with version and sha256), an install plan for this host, and a `nextAction` (`continue | pair_phone | install_skill | update_skill | human_upload`). It never installs anything itself and never asks you to hand-edit your repository's agent config. Its `spaces` tell you what a Space argument may name next; `pair_phone` means the private half is unavailable until the user pairs.",
          "readOnly": true,
          "destructive": false,
          "idempotent": true,
          "scopes": [
            "context:shared"
          ],
          "inputParams": [
            "host",
            "environment",
            "install_scope",
            "installed_skill_version",
            "installed_skill_sha256"
          ],
          "inputSchema": {
            "properties": {
              "host": {
                "type": "string",
                "enum": [
                  "claude-code",
                  "codex",
                  "cursor",
                  "claude-ai",
                  "chatgpt",
                  "generic",
                  "chat"
                ],
                "description": "The host you are running in. Decides whether the install plan is `agent_install` (a local agent that can write files) or `human_upload` (a hosted chat surface). Omit to be treated as a hosted chat surface."
              },
              "environment": {
                "type": "string",
                "maxLength": 100,
                "description": "Optional free-form environment hint (for example `macos`, `linux`, `web`)."
              },
              "install_scope": {
                "type": "string",
                "enum": [
                  "user",
                  "project"
                ],
                "description": "Where a local install would land: the user's own skills directory or this repository."
              },
              "installed_skill_version": {
                "type": "integer",
                "minimum": 1,
                "description": "Version of the `context` skill you already have installed, if any. Drives `update_skill` vs `install_skill`."
              },
              "installed_skill_sha256": {
                "type": "string",
                "pattern": "^[0-9a-fA-F]{64}$",
                "description": "SHA-256 of the installed SKILL.md, if any. A mismatch with the published digest yields `update_skill`."
              },
              "caller": {
                "type": "object",
                "description": "Required self-reported provenance for this call. It identifies the agent host and model for activity/audit display only; it never grants permission. Use the exact model id when exposed by the host, otherwise the literal `unknown`.",
                "properties": {
                  "agent": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Calling agent or host product, for example ChatGPT, Codex, Claude Code, or Cursor."
                  },
                  "model": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Exact model identifier when known; use `unknown` when the host does not expose it. Never guess."
                  }
                },
                "required": [
                  "agent",
                  "model"
                ],
                "additionalProperties": false
              }
            },
            "type": "object",
            "additionalProperties": false,
            "required": [
              "caller"
            ]
          },
          "outputSchema": {
            "type": "object",
            "properties": {
              "account": {
                "type": "object"
              },
              "pairing": {
                "type": "string",
                "enum": [
                  "paired",
                  "required"
                ]
              },
              "spaces": {
                "type": "array",
                "items": {
                  "type": "object"
                }
              },
              "modules": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "nextAction": {
                "type": "string",
                "enum": [
                  "continue",
                  "pair_phone",
                  "install_skill",
                  "update_skill",
                  "human_upload"
                ]
              },
              "guide": {
                "type": "object"
              },
              "skill": {
                "type": "object"
              },
              "install": {
                "type": "object"
              },
              "contract": {
                "type": "object",
                "properties": {
                  "version": {
                    "type": "string"
                  },
                  "limits": {
                    "type": "object"
                  }
                },
                "required": [
                  "version",
                  "limits"
                ],
                "additionalProperties": true
              },
              "endpoint": {
                "type": "string"
              }
            },
            "required": [
              "pairing",
              "spaces",
              "nextAction",
              "contract"
            ],
            "additionalProperties": true
          }
        }
      ]
    },
    {
      "key": "discovery",
      "title": "Discovery",
      "access": "shared",
      "tools": [
        {
          "name": "search_context",
          "title": "Search across Context",
          "description": "Use this when you need to find something by words rather than by id — an Epic, Issue, Artifact or memory whose id you do not have. Read-only and bounded: every response reports coverage and truncation, so it never implies exhaustive recall. Scope with `space` (omit to search every Space you hold; private Spaces need a paired iPhone) and narrow with `kinds`. Feed the returned ids into `get_epic`, `get_issue`, `get_artifact` or `get_memory`.",
          "readOnly": true,
          "destructive": false,
          "idempotent": true,
          "scopes": [
            "context:shared"
          ],
          "inputParams": [
            "query",
            "space",
            "kinds",
            "limit",
            "cursor"
          ],
          "inputSchema": {
            "properties": {
              "query": {
                "type": "string",
                "minLength": 2,
                "maxLength": 256,
                "description": "Search text (2–256 characters)."
              },
              "space": {
                "type": "string",
                "description": "Space id or name. `shared` = the Shared Space (server-readable, available with Google sign-in alone); `personal`/`work` = the private built-ins on the paired iPhone; any other named private Space resolves by id or name. Omit to read across every Space you hold."
              },
              "kinds": {
                "type": "array",
                "maxItems": 6,
                "items": {
                  "type": "string",
                  "enum": [
                    "epic",
                    "issue",
                    "artifact",
                    "memory",
                    "person",
                    "log"
                  ]
                },
                "description": "Restrict to these primitive kinds. Omit for every kind you can read."
              },
              "limit": {
                "type": "integer",
                "minimum": 1,
                "maximum": 50,
                "default": 20,
                "description": "Maximum rows to return. Server-capped."
              },
              "cursor": {
                "type": "string",
                "description": "Opaque continuation from the previous call's `next_cursor`. Never parse it."
              },
              "caller": {
                "type": "object",
                "description": "Required self-reported provenance for this call. It identifies the agent host and model for activity/audit display only; it never grants permission. Use the exact model id when exposed by the host, otherwise the literal `unknown`.",
                "properties": {
                  "agent": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Calling agent or host product, for example ChatGPT, Codex, Claude Code, or Cursor."
                  },
                  "model": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Exact model identifier when known; use `unknown` when the host does not expose it. Never guess."
                  }
                },
                "required": [
                  "agent",
                  "model"
                ],
                "additionalProperties": false
              }
            },
            "required": [
              "query",
              "caller"
            ],
            "type": "object",
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "properties": {
              "results": {
                "type": "array",
                "items": {
                  "type": "object",
                  "required": [
                    "id",
                    "kind"
                  ],
                  "additionalProperties": true
                }
              },
              "next_cursor": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "space": {
                "type": [
                  "object",
                  "null"
                ]
              }
            },
            "required": [
              "results"
            ],
            "additionalProperties": true
          }
        }
      ]
    },
    {
      "key": "space",
      "title": "Space",
      "access": "shared",
      "tools": [
        {
          "name": "list_spaces",
          "title": "List the account's Spaces",
          "description": "Use this when you need to know which Spaces exist before naming one in a `space` argument. Read-only. Always returns the Shared Space; private Spaces (`personal`, `work`, named) appear only once an iPhone is paired. Each row carries `{id, name, privacy}` — the exact shape every other result echoes back as `space`.",
          "readOnly": true,
          "destructive": false,
          "idempotent": true,
          "scopes": [
            "context:shared"
          ],
          "inputParams": [],
          "inputSchema": {
            "properties": {
              "caller": {
                "type": "object",
                "description": "Required self-reported provenance for this call. It identifies the agent host and model for activity/audit display only; it never grants permission. Use the exact model id when exposed by the host, otherwise the literal `unknown`.",
                "properties": {
                  "agent": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Calling agent or host product, for example ChatGPT, Codex, Claude Code, or Cursor."
                  },
                  "model": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Exact model identifier when known; use `unknown` when the host does not expose it. Never guess."
                  }
                },
                "required": [
                  "agent",
                  "model"
                ],
                "additionalProperties": false
              }
            },
            "type": "object",
            "additionalProperties": false,
            "required": [
              "caller"
            ]
          },
          "outputSchema": {
            "type": "object",
            "properties": {
              "spaces": {
                "type": "array",
                "items": {
                  "type": "object",
                  "required": [
                    "id",
                    "name",
                    "privacy"
                  ],
                  "additionalProperties": true
                }
              },
              "next_cursor": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "space": {
                "type": [
                  "object",
                  "null"
                ]
              }
            },
            "required": [
              "spaces"
            ],
            "additionalProperties": true
          }
        }
      ]
    },
    {
      "key": "epic",
      "title": "Epic",
      "access": "shared",
      "tools": [
        {
          "name": "list_epics",
          "title": "List Epics",
          "description": "Use this when you need to survey the goals in flight rather than open one specific Epic. Read-only, most recently updated first. Pass `space` to scope (omit to union every Space you hold; private Spaces need a paired iPhone). Returns summary rows with derived status — call `get_epic` for one hydrated Epic, or `list_issues {parent_id}` for its children.",
          "readOnly": true,
          "destructive": false,
          "idempotent": true,
          "scopes": [
            "context:shared"
          ],
          "inputParams": [
            "space",
            "labels",
            "include_closed",
            "updated_after",
            "limit",
            "cursor"
          ],
          "inputSchema": {
            "properties": {
              "space": {
                "type": "string",
                "description": "Space id or name. `shared` = the Shared Space (server-readable, available with Google sign-in alone); `personal`/`work` = the private built-ins on the paired iPhone; any other named private Space resolves by id or name. Omit to read across every Space you hold."
              },
              "labels": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "maxItems": 25,
                "description": "Labels to set (replaces the existing set)."
              },
              "include_closed": {
                "type": "boolean",
                "default": false,
                "description": "Include Epics whose Issues are all done."
              },
              "updated_after": {
                "type": "string",
                "description": "Only Epics updated at or after this ISO 8601 instant."
              },
              "limit": {
                "type": "integer",
                "minimum": 1,
                "maximum": 200,
                "default": 50,
                "description": "Maximum rows to return. Server-capped."
              },
              "cursor": {
                "type": "string",
                "description": "Opaque continuation from the previous call's `next_cursor`. Never parse it."
              },
              "caller": {
                "type": "object",
                "description": "Required self-reported provenance for this call. It identifies the agent host and model for activity/audit display only; it never grants permission. Use the exact model id when exposed by the host, otherwise the literal `unknown`.",
                "properties": {
                  "agent": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Calling agent or host product, for example ChatGPT, Codex, Claude Code, or Cursor."
                  },
                  "model": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Exact model identifier when known; use `unknown` when the host does not expose it. Never guess."
                  }
                },
                "required": [
                  "agent",
                  "model"
                ],
                "additionalProperties": false
              }
            },
            "type": "object",
            "additionalProperties": false,
            "required": [
              "caller"
            ]
          },
          "outputSchema": {
            "type": "object",
            "properties": {
              "epics": {
                "type": "array",
                "items": {
                  "type": "object",
                  "required": [
                    "id",
                    "title"
                  ],
                  "additionalProperties": true
                }
              },
              "next_cursor": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "space": {
                "type": [
                  "object",
                  "null"
                ]
              }
            },
            "required": [
              "epics"
            ],
            "additionalProperties": true
          }
        },
        {
          "name": "get_epic",
          "title": "Get one Epic",
          "description": "Use this when you need to see one goal in full — its blueprint, derived status, child Issues, Artifacts and recent activity in a single read. Read-only. The Epic's Space governs access; a private Epic needs a paired iPhone. Use its `issues[]` to pick work up with `claim_issue`, or its `artifacts[]` with `get_artifact`.",
          "readOnly": true,
          "destructive": false,
          "idempotent": true,
          "scopes": [
            "context:shared"
          ],
          "inputParams": [
            "epic_id"
          ],
          "inputSchema": {
            "properties": {
              "epic_id": {
                "type": "string",
                "minLength": 1,
                "description": "Epic id."
              },
              "caller": {
                "type": "object",
                "description": "Required self-reported provenance for this call. It identifies the agent host and model for activity/audit display only; it never grants permission. Use the exact model id when exposed by the host, otherwise the literal `unknown`.",
                "properties": {
                  "agent": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Calling agent or host product, for example ChatGPT, Codex, Claude Code, or Cursor."
                  },
                  "model": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Exact model identifier when known; use `unknown` when the host does not expose it. Never guess."
                  }
                },
                "required": [
                  "agent",
                  "model"
                ],
                "additionalProperties": false
              }
            },
            "required": [
              "epic_id",
              "caller"
            ],
            "type": "object",
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "description": "v3 result. Success carries the named collections below plus `space`; a business failure carries `{ok:false, error:{code, message, retryable, next_action?}}` (spec §4). `content` remains available to text-oriented clients.",
            "additionalProperties": true
          }
        },
        {
          "name": "create_epic",
          "title": "Create an Epic",
          "description": "Use this when you need to open a new goal in a Space, optionally seeding its first Issues in the same call. Writes: it creates one Epic (and any `issues[]` under it) and is visible to the user immediately. `space` is required — `shared` is the only destination until an iPhone is paired. Returns the new `epic_id` for `create_issues`, `attach_artifact` and `request_review`.",
          "readOnly": false,
          "destructive": false,
          "idempotent": false,
          "scopes": [
            "context:shared"
          ],
          "inputParams": [
            "space",
            "title",
            "goal",
            "labels",
            "issues",
            "dedupe_key"
          ],
          "inputSchema": {
            "properties": {
              "space": {
                "type": "string",
                "description": "Required. Destination Space: `shared` (Shared Space, the only destination until an iPhone is paired), `personal`/`work` (private built-ins), or a named private Space's id/name."
              },
              "title": {
                "type": "string",
                "maxLength": 500
              },
              "goal": {
                "type": "string",
                "maxLength": 2048,
                "description": "What done looks like for this Epic — the blueprint the Issues serve."
              },
              "labels": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "maxItems": 25,
                "description": "Labels to set (replaces the existing set)."
              },
              "issues": {
                "type": "array",
                "maxItems": 25,
                "description": "Optional first Issues, created under the new Epic in the same call.",
                "items": {
                  "type": "object",
                  "properties": {
                    "title": {
                      "type": "string",
                      "maxLength": 500
                    },
                    "description": {
                      "type": "string",
                      "maxLength": 2048
                    },
                    "acceptance_criteria": {
                      "type": "array",
                      "maxItems": 25,
                      "description": "Replaces the whole criteria set ([] clears, omit to leave unchanged). Mark `passed: true` only for criteria you actually verified — `verify_issue` scores these.",
                      "items": {
                        "type": "object",
                        "properties": {
                          "text": {
                            "type": "string",
                            "maxLength": 500
                          },
                          "passed": {
                            "type": "boolean",
                            "default": false
                          }
                        },
                        "required": [
                          "text"
                        ],
                        "additionalProperties": false
                      }
                    },
                    "labels": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      },
                      "maxItems": 25,
                      "description": "Labels to set (replaces the existing set)."
                    },
                    "assignee": {
                      "type": "string",
                      "description": "Owner: `me` (the user), an agent name (use your reported caller label when picking work up yourself), or an empty string to clear."
                    },
                    "priority": {
                      "type": "integer",
                      "minimum": 0,
                      "maximum": 4,
                      "description": "0 none … 4 urgent."
                    },
                    "due_at": {
                      "type": "string",
                      "description": "Deadline as an ISO 8601 datetime (include the user's offset when known) or date (YYYY-MM-DD)."
                    }
                  },
                  "required": [
                    "title"
                  ],
                  "additionalProperties": false
                }
              },
              "dedupe_key": {
                "type": "string",
                "maxLength": 128,
                "description": "Optional idempotency key for retries. Per-account and GLOBAL across every tool — it dedupes the WHOLE call. Use a distinct value per call, or omit unless you are actually retrying."
              },
              "caller": {
                "type": "object",
                "description": "Required self-reported provenance for this call. It identifies the agent host and model for activity/audit display only; it never grants permission. Use the exact model id when exposed by the host, otherwise the literal `unknown`.",
                "properties": {
                  "agent": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Calling agent or host product, for example ChatGPT, Codex, Claude Code, or Cursor."
                  },
                  "model": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Exact model identifier when known; use `unknown` when the host does not expose it. Never guess."
                  }
                },
                "required": [
                  "agent",
                  "model"
                ],
                "additionalProperties": false
              }
            },
            "required": [
              "space",
              "title",
              "caller"
            ],
            "type": "object",
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "description": "v3 result. Success carries the named collections below plus `space`; a business failure carries `{ok:false, error:{code, message, retryable, next_action?}}` (spec §4). `content` remains available to text-oriented clients.",
            "additionalProperties": true
          }
        },
        {
          "name": "update_epic",
          "title": "Update an Epic",
          "description": "Use this when you need to change one Epic's title, goal, labels or Space — never its status, which is derived from its Issues. Writes in place. The Epic's current Space governs access; moving it to a private Space needs a paired iPhone. Use `update_issues` for anything about the work itself.",
          "readOnly": false,
          "destructive": false,
          "idempotent": false,
          "scopes": [
            "context:shared"
          ],
          "inputParams": [
            "epic_id",
            "title",
            "goal",
            "labels",
            "space",
            "dedupe_key"
          ],
          "inputSchema": {
            "properties": {
              "epic_id": {
                "type": "string",
                "minLength": 1
              },
              "title": {
                "type": "string",
                "maxLength": 500
              },
              "goal": {
                "type": "string",
                "maxLength": 2048
              },
              "labels": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "maxItems": 25,
                "description": "Labels to set (replaces the existing set)."
              },
              "space": {
                "type": "string",
                "description": "Move the Epic to this Space. Omit to leave it where it is."
              },
              "dedupe_key": {
                "type": "string",
                "maxLength": 128,
                "description": "Optional idempotency key for retries. Per-account and GLOBAL across every tool — it dedupes the WHOLE call. Use a distinct value per call, or omit unless you are actually retrying."
              },
              "caller": {
                "type": "object",
                "description": "Required self-reported provenance for this call. It identifies the agent host and model for activity/audit display only; it never grants permission. Use the exact model id when exposed by the host, otherwise the literal `unknown`.",
                "properties": {
                  "agent": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Calling agent or host product, for example ChatGPT, Codex, Claude Code, or Cursor."
                  },
                  "model": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Exact model identifier when known; use `unknown` when the host does not expose it. Never guess."
                  }
                },
                "required": [
                  "agent",
                  "model"
                ],
                "additionalProperties": false
              }
            },
            "required": [
              "epic_id",
              "caller"
            ],
            "type": "object",
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "description": "v3 result. Success carries the named collections below plus `space`; a business failure carries `{ok:false, error:{code, message, retryable, next_action?}}` (spec §4). `content` remains available to text-oriented clients.",
            "additionalProperties": true
          }
        },
        {
          "name": "delete_epic",
          "title": "Delete an Epic",
          "description": "Use this when you need to remove an Epic that should not exist at all — this is also how you retire work that would otherwise be `canceled`, which v3 does not expose as a state. Destructive and irreversible: it cascades to the Epic's Issues, and the response reports the cascade counts. Requires delete permission on this key; confirm with the user first. Prefer `update_epic` or `complete_issues` whenever the work merely ended.",
          "readOnly": false,
          "destructive": true,
          "idempotent": true,
          "scopes": [
            "context:shared"
          ],
          "inputParams": [
            "epic_id",
            "dedupe_key"
          ],
          "inputSchema": {
            "properties": {
              "epic_id": {
                "type": "string",
                "minLength": 1
              },
              "dedupe_key": {
                "type": "string",
                "maxLength": 128,
                "description": "Optional idempotency key for retries. Per-account and GLOBAL across every tool — it dedupes the WHOLE call. Use a distinct value per call, or omit unless you are actually retrying."
              },
              "caller": {
                "type": "object",
                "description": "Required self-reported provenance for this call. It identifies the agent host and model for activity/audit display only; it never grants permission. Use the exact model id when exposed by the host, otherwise the literal `unknown`.",
                "properties": {
                  "agent": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Calling agent or host product, for example ChatGPT, Codex, Claude Code, or Cursor."
                  },
                  "model": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Exact model identifier when known; use `unknown` when the host does not expose it. Never guess."
                  }
                },
                "required": [
                  "agent",
                  "model"
                ],
                "additionalProperties": false
              }
            },
            "required": [
              "epic_id",
              "caller"
            ],
            "type": "object",
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "description": "v3 result. Success carries the named collections below plus `space`; a business failure carries `{ok:false, error:{code, message, retryable, next_action?}}` (spec §4). `content` remains available to text-oriented clients.",
            "additionalProperties": true
          }
        }
      ]
    },
    {
      "key": "issue",
      "title": "Issue",
      "access": "shared",
      "tools": [
        {
          "name": "list_issues",
          "title": "List Issues",
          "description": "Use this when you need to see the queue rather than one Issue — what is open, what is yours, what sits under an Epic. Read-only, most recently updated first; closed Issues are excluded unless `include_closed`. Filter by `parent_id` (Epic or parent Issue), `state`, `assignee`, `labels` or `space`; private Spaces need a paired iPhone. Feed ids into `get_issue`, `claim_issue` or `update_issues`.",
          "readOnly": true,
          "destructive": false,
          "idempotent": true,
          "scopes": [
            "context:shared"
          ],
          "inputParams": [
            "space",
            "parent_id",
            "state",
            "assignee",
            "labels",
            "include_closed",
            "updated_after",
            "limit",
            "cursor"
          ],
          "inputSchema": {
            "properties": {
              "space": {
                "type": "string",
                "description": "Space id or name. `shared` = the Shared Space (server-readable, available with Google sign-in alone); `personal`/`work` = the private built-ins on the paired iPhone; any other named private Space resolves by id or name. Omit to read across every Space you hold."
              },
              "parent_id": {
                "type": "string",
                "description": "Only Issues directly under this Epic or parent Issue. Decomposition is child Issues — there are no checklists."
              },
              "state": {
                "type": "string",
                "enum": [
                  "open",
                  "in_progress",
                  "in_review",
                  "done"
                ],
                "description": "Issue lifecycle state. `blocked` is derived from `blocked_by` edges, not a state."
              },
              "assignee": {
                "type": "string",
                "description": "`me`, an agent name, or `none` for unassigned. Use this to find your own queue."
              },
              "labels": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "maxItems": 25,
                "description": "Labels to set (replaces the existing set)."
              },
              "include_closed": {
                "type": "boolean",
                "default": false
              },
              "updated_after": {
                "type": "string",
                "description": "Only Issues updated at or after this ISO 8601 instant."
              },
              "limit": {
                "type": "integer",
                "minimum": 1,
                "maximum": 200,
                "default": 50,
                "description": "Maximum rows to return. Server-capped."
              },
              "cursor": {
                "type": "string",
                "description": "Opaque continuation from the previous call's `next_cursor`. Never parse it."
              },
              "caller": {
                "type": "object",
                "description": "Required self-reported provenance for this call. It identifies the agent host and model for activity/audit display only; it never grants permission. Use the exact model id when exposed by the host, otherwise the literal `unknown`.",
                "properties": {
                  "agent": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Calling agent or host product, for example ChatGPT, Codex, Claude Code, or Cursor."
                  },
                  "model": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Exact model identifier when known; use `unknown` when the host does not expose it. Never guess."
                  }
                },
                "required": [
                  "agent",
                  "model"
                ],
                "additionalProperties": false
              }
            },
            "type": "object",
            "additionalProperties": false,
            "required": [
              "caller"
            ]
          },
          "outputSchema": {
            "type": "object",
            "properties": {
              "issues": {
                "type": "array",
                "items": {
                  "type": "object",
                  "required": [
                    "id",
                    "title"
                  ],
                  "additionalProperties": true
                }
              },
              "next_cursor": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "space": {
                "type": [
                  "object",
                  "null"
                ]
              }
            },
            "required": [
              "issues"
            ],
            "additionalProperties": true
          }
        },
        {
          "name": "get_issue",
          "title": "Get one Issue",
          "description": "Use this when you need to read one Issue in full before acting on it — acceptance criteria, state, `blocked_by` edges, child Issues, Artifacts, comments and delivery/claim state in a single read. Read-only. Its Space governs access. Read `delivery.version` here before `claim_issue` or `verify_issue`, and its criteria before `update_issues`.",
          "readOnly": true,
          "destructive": false,
          "idempotent": true,
          "scopes": [
            "context:shared"
          ],
          "inputParams": [
            "issue_id"
          ],
          "inputSchema": {
            "properties": {
              "issue_id": {
                "type": "string",
                "minLength": 1
              },
              "caller": {
                "type": "object",
                "description": "Required self-reported provenance for this call. It identifies the agent host and model for activity/audit display only; it never grants permission. Use the exact model id when exposed by the host, otherwise the literal `unknown`.",
                "properties": {
                  "agent": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Calling agent or host product, for example ChatGPT, Codex, Claude Code, or Cursor."
                  },
                  "model": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Exact model identifier when known; use `unknown` when the host does not expose it. Never guess."
                  }
                },
                "required": [
                  "agent",
                  "model"
                ],
                "additionalProperties": false
              }
            },
            "required": [
              "issue_id",
              "caller"
            ],
            "type": "object",
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "description": "v3 result. Success carries the named collections below plus `space`; a business failure carries `{ok:false, error:{code, message, retryable, next_action?}}` (spec §4). `content` remains available to text-oriented clients.",
            "additionalProperties": true
          }
        },
        {
          "name": "create_issues",
          "title": "Create Issues",
          "description": "Use this when you need to add one or more units of work under an Epic or under another Issue — decomposition in v3 is always child Issues, never a checklist. Writes 1–25 Issues in one call under `parent_id`; each lands in the parent's Space, so a private parent needs a paired iPhone. Returns the new issue ids for `update_issues`, `claim_issue` and `attach_artifact`.",
          "readOnly": false,
          "destructive": false,
          "idempotent": false,
          "scopes": [
            "context:shared"
          ],
          "inputParams": [
            "parent_id",
            "issues",
            "dedupe_key"
          ],
          "inputSchema": {
            "properties": {
              "parent_id": {
                "type": "string",
                "minLength": 1,
                "description": "The Epic or Issue these Issues belong to. Their Space follows the parent."
              },
              "issues": {
                "type": "array",
                "minItems": 1,
                "maxItems": 25,
                "items": {
                  "type": "object",
                  "properties": {
                    "title": {
                      "type": "string",
                      "maxLength": 500
                    },
                    "description": {
                      "type": "string",
                      "maxLength": 2048
                    },
                    "acceptance_criteria": {
                      "type": "array",
                      "maxItems": 25,
                      "description": "Replaces the whole criteria set ([] clears, omit to leave unchanged). Mark `passed: true` only for criteria you actually verified — `verify_issue` scores these.",
                      "items": {
                        "type": "object",
                        "properties": {
                          "text": {
                            "type": "string",
                            "maxLength": 500
                          },
                          "passed": {
                            "type": "boolean",
                            "default": false
                          }
                        },
                        "required": [
                          "text"
                        ],
                        "additionalProperties": false
                      }
                    },
                    "labels": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      },
                      "maxItems": 25,
                      "description": "Labels to set (replaces the existing set)."
                    },
                    "blocked_by": {
                      "type": "array",
                      "maxItems": 25,
                      "items": {
                        "type": "string"
                      },
                      "description": "Issue ids this Issue is blocked by — replaces the whole set ([] clears). `blocked` status is derived from these edges."
                    },
                    "assignee": {
                      "type": "string",
                      "description": "Owner: `me` (the user), an agent name (use your reported caller label when picking work up yourself), or an empty string to clear."
                    },
                    "priority": {
                      "type": "integer",
                      "minimum": 0,
                      "maximum": 4,
                      "description": "0 none … 4 urgent."
                    },
                    "due_at": {
                      "type": "string",
                      "description": "Deadline as an ISO 8601 datetime (include the user's offset when known) or date (YYYY-MM-DD)."
                    }
                  },
                  "required": [
                    "title"
                  ],
                  "additionalProperties": false
                }
              },
              "dedupe_key": {
                "type": "string",
                "maxLength": 128,
                "description": "Optional idempotency key for retries. Per-account and GLOBAL across every tool — it dedupes the WHOLE call. Use a distinct value per call, or omit unless you are actually retrying."
              },
              "caller": {
                "type": "object",
                "description": "Required self-reported provenance for this call. It identifies the agent host and model for activity/audit display only; it never grants permission. Use the exact model id when exposed by the host, otherwise the literal `unknown`.",
                "properties": {
                  "agent": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Calling agent or host product, for example ChatGPT, Codex, Claude Code, or Cursor."
                  },
                  "model": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Exact model identifier when known; use `unknown` when the host does not expose it. Never guess."
                  }
                },
                "required": [
                  "agent",
                  "model"
                ],
                "additionalProperties": false
              }
            },
            "required": [
              "parent_id",
              "issues",
              "caller"
            ],
            "type": "object",
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "description": "v3 result. Success carries the named collections below plus `space`; a business failure carries `{ok:false, error:{code, message, retryable, next_action?}}` (spec §4). `content` remains available to text-oriented clients.",
            "additionalProperties": true
          }
        },
        {
          "name": "update_issues",
          "title": "Update Issues",
          "description": "Use this when you need to edit, re-state, re-parent or re-block existing Issues — including moving one to `in_progress` or `in_review`. Writes 1–25 Issues in one call; each item names its own `issue_id`, so a batch may touch several Epics. `done` is a human-accepted outcome: prefer `claim_issue` plus `complete_issues` over writing `state: \"done\"` directly. Pass `expected_version` (from `get_issue`) to fail loudly on a stale edit.",
          "readOnly": false,
          "destructive": false,
          "idempotent": false,
          "scopes": [
            "context:shared"
          ],
          "inputParams": [
            "issues",
            "dedupe_key"
          ],
          "inputSchema": {
            "properties": {
              "issues": {
                "type": "array",
                "minItems": 1,
                "maxItems": 25,
                "items": {
                  "type": "object",
                  "properties": {
                    "issue_id": {
                      "type": "string",
                      "minLength": 1
                    },
                    "title": {
                      "type": "string",
                      "maxLength": 500
                    },
                    "description": {
                      "type": "string",
                      "maxLength": 2048
                    },
                    "state": {
                      "type": "string",
                      "enum": [
                        "open",
                        "in_progress",
                        "in_review",
                        "done"
                      ],
                      "description": "Issue lifecycle state. `blocked` is derived from `blocked_by` edges, not a state."
                    },
                    "parent_id": {
                      "type": "string",
                      "description": "Move this Issue under another Epic or Issue. Empty string un-nests it."
                    },
                    "blocked_by": {
                      "type": "array",
                      "maxItems": 25,
                      "items": {
                        "type": "string"
                      },
                      "description": "Issue ids this Issue is blocked by — replaces the whole set ([] clears). `blocked` status is derived from these edges."
                    },
                    "acceptance_criteria": {
                      "type": "array",
                      "maxItems": 25,
                      "description": "Replaces the whole criteria set ([] clears, omit to leave unchanged). Mark `passed: true` only for criteria you actually verified — `verify_issue` scores these.",
                      "items": {
                        "type": "object",
                        "properties": {
                          "text": {
                            "type": "string",
                            "maxLength": 500
                          },
                          "passed": {
                            "type": "boolean",
                            "default": false
                          }
                        },
                        "required": [
                          "text"
                        ],
                        "additionalProperties": false
                      }
                    },
                    "labels": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      },
                      "maxItems": 25,
                      "description": "Labels to set (replaces the existing set)."
                    },
                    "assignee": {
                      "type": "string",
                      "description": "Owner: `me` (the user), an agent name (use your reported caller label when picking work up yourself), or an empty string to clear."
                    },
                    "priority": {
                      "type": "integer",
                      "minimum": 0,
                      "maximum": 4,
                      "description": "0 none … 4 urgent."
                    },
                    "due_at": {
                      "type": "string",
                      "description": "Deadline as an ISO 8601 datetime (include the user's offset when known) or date (YYYY-MM-DD)."
                    },
                    "expected_version": {
                      "type": "integer",
                      "minimum": 0,
                      "description": "Optimistic concurrency — the `version` you read from `get_issue`. A stale value is rejected, not merged."
                    }
                  },
                  "required": [
                    "issue_id"
                  ],
                  "additionalProperties": false
                }
              },
              "dedupe_key": {
                "type": "string",
                "maxLength": 128,
                "description": "Optional idempotency key for retries. Per-account and GLOBAL across every tool — it dedupes the WHOLE call. Use a distinct value per call, or omit unless you are actually retrying."
              },
              "caller": {
                "type": "object",
                "description": "Required self-reported provenance for this call. It identifies the agent host and model for activity/audit display only; it never grants permission. Use the exact model id when exposed by the host, otherwise the literal `unknown`.",
                "properties": {
                  "agent": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Calling agent or host product, for example ChatGPT, Codex, Claude Code, or Cursor."
                  },
                  "model": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Exact model identifier when known; use `unknown` when the host does not expose it. Never guess."
                  }
                },
                "required": [
                  "agent",
                  "model"
                ],
                "additionalProperties": false
              }
            },
            "required": [
              "issues",
              "caller"
            ],
            "type": "object",
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "description": "v3 result. Success carries the named collections below plus `space`; a business failure carries `{ok:false, error:{code, message, retryable, next_action?}}` (spec §4). `content` remains available to text-oriented clients.",
            "additionalProperties": true
          }
        },
        {
          "name": "complete_issues",
          "title": "Complete Issues",
          "description": "Use this when you need to move Issues to `done` because the work is finished and accepted. Writes 1–20 Issues at once; Epic status stays derived, so there is no Epic equivalent. Report truthful `work_stats` — the server rejects the batch when a tracked Issue is missing one, and an agent self-verification alone never satisfies the human acceptance gate. When acceptance is still pending, use `claim_issue` and `request_review` instead.",
          "readOnly": false,
          "destructive": false,
          "idempotent": false,
          "scopes": [
            "context:shared"
          ],
          "inputParams": [
            "issue_ids",
            "work_stats",
            "dedupe_key"
          ],
          "inputSchema": {
            "properties": {
              "issue_ids": {
                "type": "array",
                "minItems": 1,
                "maxItems": 20,
                "items": {
                  "type": "string"
                }
              },
              "work_stats": {
                "type": "object",
                "description": "Version 2 agent trace for this work unit. Exactly one primary contributor; subagents require labels. Report truthfully — never invent usage.",
                "properties": {
                  "schemaVersion": {
                    "type": "integer",
                    "const": 2
                  },
                  "unitId": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "wallDurationSec": {
                    "type": "number",
                    "minimum": 0
                  },
                  "contributors": {
                    "type": "array",
                    "minItems": 1,
                    "maxItems": 20,
                    "items": {
                      "type": "object",
                      "additionalProperties": true
                    }
                  }
                },
                "required": [
                  "schemaVersion",
                  "unitId",
                  "wallDurationSec",
                  "contributors"
                ],
                "additionalProperties": false
              },
              "dedupe_key": {
                "type": "string",
                "maxLength": 128,
                "description": "Optional idempotency key for retries. Per-account and GLOBAL across every tool — it dedupes the WHOLE call. Use a distinct value per call, or omit unless you are actually retrying."
              },
              "caller": {
                "type": "object",
                "description": "Required self-reported provenance for this call. It identifies the agent host and model for activity/audit display only; it never grants permission. Use the exact model id when exposed by the host, otherwise the literal `unknown`.",
                "properties": {
                  "agent": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Calling agent or host product, for example ChatGPT, Codex, Claude Code, or Cursor."
                  },
                  "model": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Exact model identifier when known; use `unknown` when the host does not expose it. Never guess."
                  }
                },
                "required": [
                  "agent",
                  "model"
                ],
                "additionalProperties": false
              }
            },
            "required": [
              "issue_ids",
              "caller"
            ],
            "type": "object",
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "description": "v3 result. Success carries the named collections below plus `space`; a business failure carries `{ok:false, error:{code, message, retryable, next_action?}}` (spec §4). `content` remains available to text-oriented clients.",
            "additionalProperties": true
          }
        },
        {
          "name": "delete_issues",
          "title": "Delete Issues",
          "description": "Use this when you need to remove Issues that should not exist at all — including work that would otherwise be `canceled`, which v3 does not expose. Destructive and irreversible: it cascades to child Issues and the response reports the cascade counts. Requires delete permission on this key; confirm with the user first. Use `complete_issues` for work that actually finished.",
          "readOnly": false,
          "destructive": true,
          "idempotent": true,
          "scopes": [
            "context:shared"
          ],
          "inputParams": [
            "issue_ids",
            "dedupe_key"
          ],
          "inputSchema": {
            "properties": {
              "issue_ids": {
                "type": "array",
                "minItems": 1,
                "maxItems": 20,
                "items": {
                  "type": "string"
                }
              },
              "dedupe_key": {
                "type": "string",
                "maxLength": 128,
                "description": "Optional idempotency key for retries. Per-account and GLOBAL across every tool — it dedupes the WHOLE call. Use a distinct value per call, or omit unless you are actually retrying."
              },
              "caller": {
                "type": "object",
                "description": "Required self-reported provenance for this call. It identifies the agent host and model for activity/audit display only; it never grants permission. Use the exact model id when exposed by the host, otherwise the literal `unknown`.",
                "properties": {
                  "agent": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Calling agent or host product, for example ChatGPT, Codex, Claude Code, or Cursor."
                  },
                  "model": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Exact model identifier when known; use `unknown` when the host does not expose it. Never guess."
                  }
                },
                "required": [
                  "agent",
                  "model"
                ],
                "additionalProperties": false
              }
            },
            "required": [
              "issue_ids",
              "caller"
            ],
            "type": "object",
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "description": "v3 result. Success carries the named collections below plus `space`; a business failure carries `{ok:false, error:{code, message, retryable, next_action?}}` (spec §4). `content` remains available to text-oriented clients.",
            "additionalProperties": true
          }
        }
      ]
    },
    {
      "key": "conversation",
      "title": "Conversation",
      "access": "shared",
      "tools": [
        {
          "name": "post_comment",
          "title": "Comment on an Epic, Issue or Artifact",
          "description": "Use this when you need to say something on the record — progress narration, an answer to the user's review comment, or a note anchored to a passage of an Artifact. Writes a visible comment and notifies the user; it changes no state and opens no gate (use `request_review` for that). The target's Space governs access. Pass `anchor` only for Artifacts, quoting the passage verbatim so the app can highlight it.",
          "readOnly": false,
          "destructive": false,
          "idempotent": false,
          "scopes": [
            "context:shared"
          ],
          "inputParams": [
            "target",
            "body",
            "anchor",
            "dedupe_key"
          ],
          "inputSchema": {
            "properties": {
              "target": {
                "type": "object",
                "description": "What this acts on: an Epic, an Issue, or an Artifact, by primitive kind and id.",
                "properties": {
                  "kind": {
                    "type": "string",
                    "enum": [
                      "epic",
                      "issue",
                      "artifact"
                    ]
                  },
                  "id": {
                    "type": "string",
                    "minLength": 1
                  }
                },
                "required": [
                  "kind",
                  "id"
                ],
                "additionalProperties": false
              },
              "body": {
                "type": "string",
                "maxLength": 4000
              },
              "anchor": {
                "type": "object",
                "description": "Artifact targets only — anchors this comment to a passage. Omit for a whole-document or Epic/Issue comment.",
                "properties": {
                  "quote": {
                    "type": "string",
                    "maxLength": 480,
                    "description": "The exact passage, copied verbatim from the Artifact content."
                  },
                  "prefix": {
                    "type": "string",
                    "maxLength": 64,
                    "description": "The ~32 characters immediately before `quote`. Strongly recommended for short or repeated quotes."
                  },
                  "suffix": {
                    "type": "string",
                    "maxLength": 64,
                    "description": "The ~32 characters immediately after `quote`."
                  },
                  "parent_id": {
                    "type": "string",
                    "description": "Comment id you are replying to. Threads are one level deep."
                  }
                },
                "required": [
                  "quote"
                ],
                "additionalProperties": false
              },
              "dedupe_key": {
                "type": "string",
                "maxLength": 128,
                "description": "Optional idempotency key for retries. Per-account and GLOBAL across every tool — it dedupes the WHOLE call. Use a distinct value per call, or omit unless you are actually retrying."
              },
              "caller": {
                "type": "object",
                "description": "Required self-reported provenance for this call. It identifies the agent host and model for activity/audit display only; it never grants permission. Use the exact model id when exposed by the host, otherwise the literal `unknown`.",
                "properties": {
                  "agent": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Calling agent or host product, for example ChatGPT, Codex, Claude Code, or Cursor."
                  },
                  "model": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Exact model identifier when known; use `unknown` when the host does not expose it. Never guess."
                  }
                },
                "required": [
                  "agent",
                  "model"
                ],
                "additionalProperties": false
              }
            },
            "required": [
              "target",
              "body",
              "caller"
            ],
            "type": "object",
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "description": "v3 result. Success carries the named collections below plus `space`; a business failure carries `{ok:false, error:{code, message, retryable, next_action?}}` (spec §4). `content` remains available to text-oriented clients.",
            "additionalProperties": true
          }
        }
      ]
    },
    {
      "key": "review",
      "title": "Review",
      "access": "shared",
      "tools": [
        {
          "name": "request_review",
          "title": "Request a human review",
          "description": "Use this when you need to get a person to decide something before work continues — an Epic's plan, an Issue's outcome, or an Artifact's content. Writes: it opens a human gate in the user's \"Needs You\" tray. Never mark a gate satisfied yourself and never assume approval; poll `get_changes` for the decision. Set `blocking: true` when downstream work must wait.",
          "readOnly": false,
          "destructive": false,
          "idempotent": false,
          "scopes": [
            "context:shared"
          ],
          "inputParams": [
            "target",
            "reason",
            "blocking",
            "dedupe_key"
          ],
          "inputSchema": {
            "properties": {
              "target": {
                "type": "object",
                "description": "What this acts on: an Epic, an Issue, or an Artifact, by primitive kind and id.",
                "properties": {
                  "kind": {
                    "type": "string",
                    "enum": [
                      "epic",
                      "issue",
                      "artifact"
                    ]
                  },
                  "id": {
                    "type": "string",
                    "minLength": 1
                  }
                },
                "required": [
                  "kind",
                  "id"
                ],
                "additionalProperties": false
              },
              "reason": {
                "type": "string",
                "maxLength": 500,
                "description": "Why a human decision is needed here."
              },
              "blocking": {
                "type": "boolean",
                "default": false,
                "description": "True when downstream work must wait for the decision."
              },
              "dedupe_key": {
                "type": "string",
                "maxLength": 128,
                "description": "Optional idempotency key for retries. Per-account and GLOBAL across every tool — it dedupes the WHOLE call. Use a distinct value per call, or omit unless you are actually retrying."
              },
              "caller": {
                "type": "object",
                "description": "Required self-reported provenance for this call. It identifies the agent host and model for activity/audit display only; it never grants permission. Use the exact model id when exposed by the host, otherwise the literal `unknown`.",
                "properties": {
                  "agent": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Calling agent or host product, for example ChatGPT, Codex, Claude Code, or Cursor."
                  },
                  "model": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Exact model identifier when known; use `unknown` when the host does not expose it. Never guess."
                  }
                },
                "required": [
                  "agent",
                  "model"
                ],
                "additionalProperties": false
              }
            },
            "required": [
              "target",
              "reason",
              "caller"
            ],
            "type": "object",
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "description": "v3 result. Success carries the named collections below plus `space`; a business failure carries `{ok:false, error:{code, message, retryable, next_action?}}` (spec §4). `content` remains available to text-oriented clients.",
            "additionalProperties": true
          }
        },
        {
          "name": "claim_issue",
          "title": "Claim Issue completion",
          "description": "Use this when you need to put on the record, with evidence, that an Issue's acceptance criteria are met (ADR-0008). Writes a claim; it does NOT mark the Issue done — a human accepts it. Read `get_issue`'s delivery `version` first and pass it as `expected_version`; a stale value is rejected. Retry with the same `request_id` to replay rather than duplicate. Follow with `verify_issue` and `request_review`.",
          "readOnly": false,
          "destructive": false,
          "idempotent": false,
          "scopes": [
            "context:shared"
          ],
          "inputParams": [
            "issue_id",
            "request_id",
            "expected_version",
            "summary",
            "evidence"
          ],
          "inputSchema": {
            "properties": {
              "issue_id": {
                "type": "string",
                "format": "uuid"
              },
              "request_id": {
                "type": "string",
                "minLength": 1,
                "maxLength": 100,
                "description": "Idempotency key — retried with the same value replays the original result."
              },
              "expected_version": {
                "type": "integer",
                "minimum": 0
              },
              "summary": {
                "type": "string",
                "minLength": 1,
                "maxLength": 8000
              },
              "evidence": {
                "type": "array",
                "minItems": 1,
                "maxItems": 50,
                "items": {
                  "type": "object",
                  "properties": {
                    "kind": {
                      "type": "string",
                      "enum": [
                        "test",
                        "observation",
                        "artifact",
                        "source",
                        "attestation"
                      ]
                    },
                    "reference": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 2000
                    },
                    "summary": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 4000
                    },
                    "documentId": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "revision": {
                      "type": "integer",
                      "minimum": 1
                    }
                  },
                  "required": [
                    "kind",
                    "reference",
                    "summary"
                  ],
                  "additionalProperties": false
                }
              },
              "caller": {
                "type": "object",
                "description": "Required self-reported provenance for this call. It identifies the agent host and model for activity/audit display only; it never grants permission. Use the exact model id when exposed by the host, otherwise the literal `unknown`.",
                "properties": {
                  "agent": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Calling agent or host product, for example ChatGPT, Codex, Claude Code, or Cursor."
                  },
                  "model": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Exact model identifier when known; use `unknown` when the host does not expose it. Never guess."
                  }
                },
                "required": [
                  "agent",
                  "model"
                ],
                "additionalProperties": false
              }
            },
            "required": [
              "issue_id",
              "request_id",
              "expected_version",
              "summary",
              "evidence",
              "caller"
            ],
            "type": "object",
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "description": "v3 result. Success carries the named collections below plus `space`; a business failure carries `{ok:false, error:{code, message, retryable, next_action?}}` (spec §4). `content` remains available to text-oriented clients.",
            "additionalProperties": true
          }
        },
        {
          "name": "verify_issue",
          "title": "Record Issue verification",
          "description": "Use this when you need to record how you actually checked a claim — the method, the per-criterion results and the evidence. Writes a verification against one claim. An agent self-check never implies independent acceptance — a human must still accept, so set `independence` truthfully. Read the claim id and delivery `version` from `get_issue` first.",
          "readOnly": false,
          "destructive": false,
          "idempotent": false,
          "scopes": [
            "context:shared"
          ],
          "inputParams": [
            "issue_id",
            "request_id",
            "expected_version",
            "claim_id",
            "method",
            "outcome",
            "independence",
            "results",
            "evidence"
          ],
          "inputSchema": {
            "properties": {
              "issue_id": {
                "type": "string",
                "format": "uuid"
              },
              "request_id": {
                "type": "string",
                "minLength": 1,
                "maxLength": 100
              },
              "expected_version": {
                "type": "integer",
                "minimum": 0
              },
              "claim_id": {
                "type": "string",
                "minLength": 1,
                "description": "The claim being verified (from `get_issue`)."
              },
              "method": {
                "type": "string",
                "minLength": 1,
                "maxLength": 8000
              },
              "outcome": {
                "type": "string",
                "enum": [
                  "passed",
                  "failed",
                  "inconclusive"
                ]
              },
              "independence": {
                "type": "string",
                "enum": [
                  "independent",
                  "self"
                ]
              },
              "results": {
                "type": "array",
                "maxItems": 200,
                "items": {
                  "type": "object",
                  "properties": {
                    "criterion_id": {
                      "type": "string"
                    },
                    "outcome": {
                      "type": "string",
                      "enum": [
                        "passed",
                        "failed",
                        "inconclusive"
                      ]
                    },
                    "note": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 4000
                    }
                  },
                  "required": [
                    "criterion_id",
                    "outcome",
                    "note"
                  ],
                  "additionalProperties": false
                }
              },
              "evidence": {
                "type": "array",
                "minItems": 1,
                "maxItems": 50,
                "items": {
                  "type": "object",
                  "properties": {
                    "kind": {
                      "type": "string",
                      "enum": [
                        "test",
                        "observation",
                        "artifact",
                        "source",
                        "attestation"
                      ]
                    },
                    "reference": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 2000
                    },
                    "summary": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 4000
                    },
                    "documentId": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "revision": {
                      "type": "integer",
                      "minimum": 1
                    }
                  },
                  "required": [
                    "kind",
                    "reference",
                    "summary"
                  ],
                  "additionalProperties": false
                }
              },
              "caller": {
                "type": "object",
                "description": "Required self-reported provenance for this call. It identifies the agent host and model for activity/audit display only; it never grants permission. Use the exact model id when exposed by the host, otherwise the literal `unknown`.",
                "properties": {
                  "agent": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Calling agent or host product, for example ChatGPT, Codex, Claude Code, or Cursor."
                  },
                  "model": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Exact model identifier when known; use `unknown` when the host does not expose it. Never guess."
                  }
                },
                "required": [
                  "agent",
                  "model"
                ],
                "additionalProperties": false
              }
            },
            "required": [
              "issue_id",
              "request_id",
              "expected_version",
              "claim_id",
              "method",
              "outcome",
              "independence",
              "results",
              "evidence",
              "caller"
            ],
            "type": "object",
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "description": "v3 result. Success carries the named collections below plus `space`; a business failure carries `{ok:false, error:{code, message, retryable, next_action?}}` (spec §4). `content` remains available to text-oriented clients.",
            "additionalProperties": true
          }
        }
      ]
    },
    {
      "key": "artifact",
      "title": "Artifact",
      "access": "shared",
      "tools": [
        {
          "name": "list_artifacts",
          "title": "List Artifacts",
          "description": "Use this when you need to find the reviewable documents attached to a Space or to one Epic or Issue. Read-only, metadata only — no bodies, so it stays cheap. Scope with `space` or `target`; private Spaces need a paired iPhone. Feed ids into `get_artifact` for content or a resource link.",
          "readOnly": true,
          "destructive": false,
          "idempotent": true,
          "scopes": [
            "context:shared"
          ],
          "inputParams": [
            "space",
            "target",
            "limit",
            "cursor"
          ],
          "inputSchema": {
            "properties": {
              "space": {
                "type": "string",
                "description": "Space id or name. `shared` = the Shared Space (server-readable, available with Google sign-in alone); `personal`/`work` = the private built-ins on the paired iPhone; any other named private Space resolves by id or name. Omit to read across every Space you hold."
              },
              "target": {
                "type": "object",
                "description": "Only Artifacts attached to this Epic or Issue. `kind: \"artifact\"` is not a valid filter here.",
                "properties": {
                  "kind": {
                    "type": "string",
                    "enum": [
                      "epic",
                      "issue",
                      "artifact"
                    ]
                  },
                  "id": {
                    "type": "string",
                    "minLength": 1
                  }
                },
                "required": [
                  "kind",
                  "id"
                ],
                "additionalProperties": false
              },
              "limit": {
                "type": "integer",
                "minimum": 1,
                "maximum": 200,
                "default": 50,
                "description": "Maximum rows to return. Server-capped."
              },
              "cursor": {
                "type": "string",
                "description": "Opaque continuation from the previous call's `next_cursor`. Never parse it."
              },
              "caller": {
                "type": "object",
                "description": "Required self-reported provenance for this call. It identifies the agent host and model for activity/audit display only; it never grants permission. Use the exact model id when exposed by the host, otherwise the literal `unknown`.",
                "properties": {
                  "agent": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Calling agent or host product, for example ChatGPT, Codex, Claude Code, or Cursor."
                  },
                  "model": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Exact model identifier when known; use `unknown` when the host does not expose it. Never guess."
                  }
                },
                "required": [
                  "agent",
                  "model"
                ],
                "additionalProperties": false
              }
            },
            "type": "object",
            "additionalProperties": false,
            "required": [
              "caller"
            ]
          },
          "outputSchema": {
            "type": "object",
            "properties": {
              "artifacts": {
                "type": "array",
                "items": {
                  "type": "object",
                  "required": [
                    "id",
                    "title"
                  ],
                  "additionalProperties": true
                }
              },
              "next_cursor": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "space": {
                "type": [
                  "object",
                  "null"
                ]
              }
            },
            "required": [
              "artifacts"
            ],
            "additionalProperties": true
          }
        },
        {
          "name": "get_artifact",
          "title": "Get one Artifact",
          "description": "Use this when you need to read one Artifact — its metadata, its content or a resource link to it, its revision list and its comment threads. Read-only. Its Space governs access. Pass `revision_id` to read a specific immutable revision instead of the head — it never silently substitutes the head. Set `include_content: false` to keep a large document out of your context and take the resource link instead; answer the comments you read here with `post_comment`.",
          "readOnly": true,
          "destructive": false,
          "idempotent": true,
          "scopes": [
            "context:shared"
          ],
          "inputParams": [
            "artifact_id",
            "revision_id",
            "include_content"
          ],
          "inputSchema": {
            "properties": {
              "artifact_id": {
                "type": "string",
                "minLength": 1
              },
              "revision_id": {
                "type": "string",
                "description": "Read this immutable revision instead of the current head."
              },
              "include_content": {
                "type": "boolean",
                "default": true,
                "description": "False returns metadata plus a resource link only — use it for large or binary Artifacts."
              },
              "caller": {
                "type": "object",
                "description": "Required self-reported provenance for this call. It identifies the agent host and model for activity/audit display only; it never grants permission. Use the exact model id when exposed by the host, otherwise the literal `unknown`.",
                "properties": {
                  "agent": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Calling agent or host product, for example ChatGPT, Codex, Claude Code, or Cursor."
                  },
                  "model": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Exact model identifier when known; use `unknown` when the host does not expose it. Never guess."
                  }
                },
                "required": [
                  "agent",
                  "model"
                ],
                "additionalProperties": false
              }
            },
            "required": [
              "artifact_id",
              "caller"
            ],
            "type": "object",
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "description": "v3 result. Success carries the named collections below plus `space`; a business failure carries `{ok:false, error:{code, message, retryable, next_action?}}` (spec §4). `content` remains available to text-oriented clients.",
            "additionalProperties": true
          }
        },
        {
          "name": "attach_artifact",
          "title": "Attach an Artifact",
          "description": "Use this when you need to attach a reviewable document to a piece of work — a spec, a decision record, a report, a file. Writes: for text you authored, pass `content` and it is stored inline in one call; for binary or large files, pass `filename`/`size`/`sha256` and it returns an upload plan (`upload_url`, `complete_url`, chunk size, limits) for you to follow. The target's Space governs access; `shared` is the only destination until an iPhone is paired. The new `artifact_id` is what `get_artifact`, `revise_artifact` and `post_comment` take next.",
          "readOnly": false,
          "destructive": false,
          "idempotent": false,
          "scopes": [
            "context:shared"
          ],
          "inputParams": [
            "target",
            "title",
            "content",
            "mime",
            "base64",
            "filename",
            "size",
            "sha256",
            "space",
            "dedupe_key"
          ],
          "inputSchema": {
            "properties": {
              "target": {
                "type": "object",
                "description": "What this acts on: an Epic, an Issue, or an Artifact, by primitive kind and id.",
                "properties": {
                  "kind": {
                    "type": "string",
                    "enum": [
                      "epic",
                      "issue",
                      "artifact"
                    ]
                  },
                  "id": {
                    "type": "string",
                    "minLength": 1
                  }
                },
                "required": [
                  "kind",
                  "id"
                ],
                "additionalProperties": false
              },
              "title": {
                "type": "string",
                "maxLength": 300
              },
              "content": {
                "type": "string",
                "description": "Inline text you authored (markdown or HTML). Use this path whenever the Artifact is text — it avoids a lossy, token-expensive encoding step."
              },
              "mime": {
                "type": "string",
                "maxLength": 200,
                "description": "Content type of `content` or of the file being uploaded, for example `text/markdown` or `application/pdf`."
              },
              "base64": {
                "type": "string",
                "description": "Small binary payload, base64-encoded. For anything large prefer the upload plan (`filename`+`size`+`sha256`)."
              },
              "filename": {
                "type": "string",
                "maxLength": 300,
                "description": "Original filename. With `size` and `sha256` this selects the upload-plan path."
              },
              "size": {
                "type": "integer",
                "minimum": 1,
                "description": "Exact byte size of the file being uploaded."
              },
              "sha256": {
                "type": "string",
                "pattern": "^[0-9a-fA-F]{64}$",
                "description": "SHA-256 of the file being uploaded."
              },
              "space": {
                "type": "string",
                "description": "Destination Space when the target does not already fix one. Defaults to the target's Space."
              },
              "dedupe_key": {
                "type": "string",
                "maxLength": 128,
                "description": "Optional idempotency key for retries. Per-account and GLOBAL across every tool — it dedupes the WHOLE call. Use a distinct value per call, or omit unless you are actually retrying."
              },
              "caller": {
                "type": "object",
                "description": "Required self-reported provenance for this call. It identifies the agent host and model for activity/audit display only; it never grants permission. Use the exact model id when exposed by the host, otherwise the literal `unknown`.",
                "properties": {
                  "agent": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Calling agent or host product, for example ChatGPT, Codex, Claude Code, or Cursor."
                  },
                  "model": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Exact model identifier when known; use `unknown` when the host does not expose it. Never guess."
                  }
                },
                "required": [
                  "agent",
                  "model"
                ],
                "additionalProperties": false
              }
            },
            "required": [
              "target",
              "caller"
            ],
            "type": "object",
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "description": "v3 result. Success carries the named collections below plus `space`; a business failure carries `{ok:false, error:{code, message, retryable, next_action?}}` (spec §4). `content` remains available to text-oriented clients.",
            "additionalProperties": true
          }
        },
        {
          "name": "revise_artifact",
          "title": "Revise an Artifact",
          "description": "Use this when you need to change an Artifact's content — v3 appends an immutable revision and advances the head rather than overwriting, so the old text stays citable. Writes. `expected_revision_id` is mandatory optimistic concurrency: a stale head is rejected with the actual head and nothing is written. Use `update_artifact` for metadata only, and `post_comment` to answer review threads.",
          "readOnly": false,
          "destructive": false,
          "idempotent": false,
          "scopes": [
            "context:shared"
          ],
          "inputParams": [
            "artifact_id",
            "expected_revision_id",
            "content",
            "base64",
            "mime",
            "change_summary",
            "revision_id",
            "dedupe_key"
          ],
          "inputSchema": {
            "properties": {
              "artifact_id": {
                "type": "string",
                "minLength": 1
              },
              "expected_revision_id": {
                "type": "string",
                "minLength": 1,
                "description": "The head revision id you read from `get_artifact`. Stale values are rejected."
              },
              "content": {
                "type": "string",
                "description": "New UTF-8 text content. Use this or `base64`."
              },
              "base64": {
                "type": "string",
                "description": "New file bytes, base64-encoded. Use this or `content`."
              },
              "mime": {
                "type": "string",
                "maxLength": 200
              },
              "change_summary": {
                "type": "string",
                "maxLength": 500
              },
              "revision_id": {
                "type": "string",
                "description": "Stable id for this revision — reuse it when retrying an ambiguous call."
              },
              "dedupe_key": {
                "type": "string",
                "maxLength": 128,
                "description": "Optional idempotency key for retries. Per-account and GLOBAL across every tool — it dedupes the WHOLE call. Use a distinct value per call, or omit unless you are actually retrying."
              },
              "caller": {
                "type": "object",
                "description": "Required self-reported provenance for this call. It identifies the agent host and model for activity/audit display only; it never grants permission. Use the exact model id when exposed by the host, otherwise the literal `unknown`.",
                "properties": {
                  "agent": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Calling agent or host product, for example ChatGPT, Codex, Claude Code, or Cursor."
                  },
                  "model": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Exact model identifier when known; use `unknown` when the host does not expose it. Never guess."
                  }
                },
                "required": [
                  "agent",
                  "model"
                ],
                "additionalProperties": false
              }
            },
            "required": [
              "artifact_id",
              "expected_revision_id",
              "caller"
            ],
            "type": "object",
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "description": "v3 result. Success carries the named collections below plus `space`; a business failure carries `{ok:false, error:{code, message, retryable, next_action?}}` (spec §4). `content` remains available to text-oriented clients.",
            "additionalProperties": true
          }
        },
        {
          "name": "update_artifact",
          "title": "Update Artifact metadata",
          "description": "Use this when you need to change only an Artifact's title, labels, kind or Space, leaving its content exactly as it is. Writes metadata in place — no new revision, so nothing citable moves. Use `revise_artifact` for content.",
          "readOnly": false,
          "destructive": false,
          "idempotent": false,
          "scopes": [
            "context:shared"
          ],
          "inputParams": [
            "artifact_id",
            "title",
            "labels",
            "kind",
            "space",
            "dedupe_key"
          ],
          "inputSchema": {
            "properties": {
              "artifact_id": {
                "type": "string",
                "minLength": 1
              },
              "title": {
                "type": "string",
                "maxLength": 300
              },
              "labels": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "maxItems": 20
              },
              "kind": {
                "type": "string",
                "maxLength": 40,
                "description": "What this Artifact IS: `adr`, `rfc`, `spec`, `prd`, `postmortem`, `runbook`, `note`, `review`, or anything else. Case-insensitive."
              },
              "space": {
                "type": "string",
                "description": "Move the Artifact to this Space."
              },
              "dedupe_key": {
                "type": "string",
                "maxLength": 128,
                "description": "Optional idempotency key for retries. Per-account and GLOBAL across every tool — it dedupes the WHOLE call. Use a distinct value per call, or omit unless you are actually retrying."
              },
              "caller": {
                "type": "object",
                "description": "Required self-reported provenance for this call. It identifies the agent host and model for activity/audit display only; it never grants permission. Use the exact model id when exposed by the host, otherwise the literal `unknown`.",
                "properties": {
                  "agent": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Calling agent or host product, for example ChatGPT, Codex, Claude Code, or Cursor."
                  },
                  "model": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Exact model identifier when known; use `unknown` when the host does not expose it. Never guess."
                  }
                },
                "required": [
                  "agent",
                  "model"
                ],
                "additionalProperties": false
              }
            },
            "required": [
              "artifact_id",
              "caller"
            ],
            "type": "object",
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "description": "v3 result. Success carries the named collections below plus `space`; a business failure carries `{ok:false, error:{code, message, retryable, next_action?}}` (spec §4). `content` remains available to text-oriented clients.",
            "additionalProperties": true
          }
        },
        {
          "name": "delete_artifacts",
          "title": "Delete Artifacts",
          "description": "Use this when you need to remove Artifacts from the account entirely. Destructive and irreversible — revisions and comment threads go with them, and the response reports the cascade counts. Requires delete permission on this key; confirm with the user first. Prefer `update_artifact` or a new revision when the document merely became obsolete.",
          "readOnly": false,
          "destructive": true,
          "idempotent": true,
          "scopes": [
            "context:shared"
          ],
          "inputParams": [
            "artifact_ids",
            "dedupe_key"
          ],
          "inputSchema": {
            "properties": {
              "artifact_ids": {
                "type": "array",
                "minItems": 1,
                "maxItems": 20,
                "items": {
                  "type": "string"
                }
              },
              "dedupe_key": {
                "type": "string",
                "maxLength": 128,
                "description": "Optional idempotency key for retries. Per-account and GLOBAL across every tool — it dedupes the WHOLE call. Use a distinct value per call, or omit unless you are actually retrying."
              },
              "caller": {
                "type": "object",
                "description": "Required self-reported provenance for this call. It identifies the agent host and model for activity/audit display only; it never grants permission. Use the exact model id when exposed by the host, otherwise the literal `unknown`.",
                "properties": {
                  "agent": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Calling agent or host product, for example ChatGPT, Codex, Claude Code, or Cursor."
                  },
                  "model": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Exact model identifier when known; use `unknown` when the host does not expose it. Never guess."
                  }
                },
                "required": [
                  "agent",
                  "model"
                ],
                "additionalProperties": false
              }
            },
            "required": [
              "artifact_ids",
              "caller"
            ],
            "type": "object",
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "description": "v3 result. Success carries the named collections below plus `space`; a business failure carries `{ok:false, error:{code, message, retryable, next_action?}}` (spec §4). `content` remains available to text-oriented clients.",
            "additionalProperties": true
          }
        },
        {
          "name": "get_artifact_transfer",
          "title": "Inspect an Artifact upload",
          "description": "Use this when you need to check whether an `attach_artifact` upload plan you followed actually completed. Read-only; it reports status, size, digest and expiry for an opaque handle you own, and never exposes storage keys. When it reports completion the Artifact is readable with `get_artifact`.",
          "readOnly": true,
          "destructive": false,
          "idempotent": true,
          "scopes": [
            "context:shared"
          ],
          "inputParams": [
            "transfer_id"
          ],
          "inputSchema": {
            "properties": {
              "transfer_id": {
                "type": "string",
                "minLength": 1,
                "description": "The transfer handle returned by `attach_artifact`."
              },
              "caller": {
                "type": "object",
                "description": "Required self-reported provenance for this call. It identifies the agent host and model for activity/audit display only; it never grants permission. Use the exact model id when exposed by the host, otherwise the literal `unknown`.",
                "properties": {
                  "agent": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Calling agent or host product, for example ChatGPT, Codex, Claude Code, or Cursor."
                  },
                  "model": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Exact model identifier when known; use `unknown` when the host does not expose it. Never guess."
                  }
                },
                "required": [
                  "agent",
                  "model"
                ],
                "additionalProperties": false
              }
            },
            "required": [
              "transfer_id",
              "caller"
            ],
            "type": "object",
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "description": "v3 result. Success carries the named collections below plus `space`; a business failure carries `{ok:false, error:{code, message, retryable, next_action?}}` (spec §4). `content` remains available to text-oriented clients.",
            "additionalProperties": true
          }
        }
      ]
    },
    {
      "key": "changes",
      "title": "Changes",
      "access": "shared",
      "tools": [
        {
          "name": "get_changes",
          "title": "Read what changed",
          "description": "Use this when you need to know what happened while you were working — review decisions, comments, and operations the user's phone applied. Read-only, cursor-based with a bounded wait: `wait_ms` blocks until something arrives (25 s ceiling) instead of you polling in a loop. Persist `next_cursor` only after processing the page; replay from the previous cursor after a crash. This is how you wait for a `request_review` decision — never assume approval.",
          "readOnly": true,
          "destructive": false,
          "idempotent": true,
          "scopes": [
            "context:shared"
          ],
          "inputParams": [
            "cursor",
            "wait_ms",
            "limit"
          ],
          "inputSchema": {
            "properties": {
              "cursor": {
                "type": "string",
                "description": "Opaque continuation from the previous call's `next_cursor`. Never parse it."
              },
              "wait_ms": {
                "type": "integer",
                "minimum": 0,
                "maximum": 25000,
                "default": 0,
                "description": "Bounded wait in milliseconds (25 s ceiling). 0 returns immediately."
              },
              "limit": {
                "type": "integer",
                "minimum": 1,
                "maximum": 200,
                "default": 50,
                "description": "Maximum rows to return. Server-capped."
              },
              "caller": {
                "type": "object",
                "description": "Required self-reported provenance for this call. It identifies the agent host and model for activity/audit display only; it never grants permission. Use the exact model id when exposed by the host, otherwise the literal `unknown`.",
                "properties": {
                  "agent": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Calling agent or host product, for example ChatGPT, Codex, Claude Code, or Cursor."
                  },
                  "model": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Exact model identifier when known; use `unknown` when the host does not expose it. Never guess."
                  }
                },
                "required": [
                  "agent",
                  "model"
                ],
                "additionalProperties": false
              }
            },
            "type": "object",
            "additionalProperties": false,
            "required": [
              "caller"
            ]
          },
          "outputSchema": {
            "type": "object",
            "properties": {
              "changes": {
                "type": "array",
                "items": {
                  "type": "object"
                }
              },
              "next_cursor": {
                "type": "string"
              },
              "waited_ms": {
                "type": "integer"
              }
            },
            "required": [
              "changes",
              "next_cursor"
            ],
            "additionalProperties": true
          }
        },
        {
          "name": "list_mutation_receipts",
          "title": "List mutation receipts",
          "description": "Use this when you need to know whether a queued write actually reached the user's device, instead of assuming that acceptance meant application. Read-only. Pass `ids` for specific receipts, or `updated_after`/`states` to sweep what changed. Anything still `accepted`/`delivered` has not been applied yet — reconcile before telling the user it landed.",
          "readOnly": true,
          "destructive": false,
          "idempotent": true,
          "scopes": [
            "context:shared"
          ],
          "inputParams": [
            "ids",
            "updated_after",
            "states",
            "limit"
          ],
          "inputSchema": {
            "properties": {
              "ids": {
                "type": "array",
                "maxItems": 50,
                "items": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 128
                },
                "description": "Specific receipt ids (returned by mutation tools). Omit to sweep by watermark."
              },
              "updated_after": {
                "type": "string",
                "description": "Only receipts changed at or after this ISO 8601 instant. Persist the last one you processed."
              },
              "states": {
                "type": "array",
                "maxItems": 9,
                "items": {
                  "type": "string",
                  "enum": [
                    "accepted",
                    "delivered",
                    "applying",
                    "applied",
                    "device_rejected",
                    "delivery_failed",
                    "expired",
                    "canceled",
                    "rejected"
                  ]
                }
              },
              "limit": {
                "type": "integer",
                "minimum": 1,
                "maximum": 100,
                "default": 50,
                "description": "Maximum rows to return. Server-capped."
              },
              "caller": {
                "type": "object",
                "description": "Required self-reported provenance for this call. It identifies the agent host and model for activity/audit display only; it never grants permission. Use the exact model id when exposed by the host, otherwise the literal `unknown`.",
                "properties": {
                  "agent": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Calling agent or host product, for example ChatGPT, Codex, Claude Code, or Cursor."
                  },
                  "model": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Exact model identifier when known; use `unknown` when the host does not expose it. Never guess."
                  }
                },
                "required": [
                  "agent",
                  "model"
                ],
                "additionalProperties": false
              }
            },
            "type": "object",
            "additionalProperties": false,
            "required": [
              "caller"
            ]
          },
          "outputSchema": {
            "type": "object",
            "properties": {
              "receipts": {
                "type": "array",
                "items": {
                  "type": "object",
                  "required": [
                    "id",
                    "state"
                  ],
                  "additionalProperties": true
                }
              },
              "next_cursor": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "space": {
                "type": [
                  "object",
                  "null"
                ]
              }
            },
            "required": [
              "receipts"
            ],
            "additionalProperties": true
          }
        }
      ]
    },
    {
      "key": "space_paired",
      "title": "Space",
      "access": "paired",
      "tools": [
        {
          "name": "create_space",
          "title": "Create a private Space",
          "description": "Use this when you need to give work its own container because it genuinely does not belong in `shared`, `personal` or `work`. Writes a new private Space on the paired iPhone, so it requires pairing — there is exactly one Shared Space and it is never created this way. Its id/name is what every other tool's `space` argument takes next.",
          "readOnly": false,
          "destructive": false,
          "idempotent": false,
          "scopes": [
            "context:private"
          ],
          "inputParams": [
            "name",
            "key",
            "dedupe_key"
          ],
          "inputSchema": {
            "properties": {
              "name": {
                "type": "string",
                "maxLength": 100
              },
              "key": {
                "type": "string",
                "maxLength": 10,
                "description": "Optional short prefix (1–10 alphanumerics, starting with a letter). Derived on the phone when omitted."
              },
              "dedupe_key": {
                "type": "string",
                "maxLength": 128,
                "description": "Optional idempotency key for retries. Per-account and GLOBAL across every tool — it dedupes the WHOLE call. Use a distinct value per call, or omit unless you are actually retrying."
              },
              "caller": {
                "type": "object",
                "description": "Required self-reported provenance for this call. It identifies the agent host and model for activity/audit display only; it never grants permission. Use the exact model id when exposed by the host, otherwise the literal `unknown`.",
                "properties": {
                  "agent": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Calling agent or host product, for example ChatGPT, Codex, Claude Code, or Cursor."
                  },
                  "model": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Exact model identifier when known; use `unknown` when the host does not expose it. Never guess."
                  }
                },
                "required": [
                  "agent",
                  "model"
                ],
                "additionalProperties": false
              }
            },
            "required": [
              "name",
              "caller"
            ],
            "type": "object",
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "description": "v3 result. Success carries the named collections below plus `space`; a business failure carries `{ok:false, error:{code, message, retryable, next_action?}}` (spec §4). `content` remains available to text-oriented clients.",
            "additionalProperties": true
          }
        },
        {
          "name": "delete_space",
          "title": "Delete a private Space",
          "description": "Use this when you need to remove an empty private Space. Destructive: refused for the built-in `personal`/`work` Spaces and for any Space that still holds Epics, Issues or Artifacts — move or delete those first. Requires pairing and delete permission; the Shared Space can never be deleted.",
          "readOnly": false,
          "destructive": true,
          "idempotent": true,
          "scopes": [
            "context:private"
          ],
          "inputParams": [
            "space",
            "dedupe_key"
          ],
          "inputSchema": {
            "properties": {
              "space": {
                "type": "string",
                "description": "Private Space id or name to delete."
              },
              "dedupe_key": {
                "type": "string",
                "maxLength": 128,
                "description": "Optional idempotency key for retries. Per-account and GLOBAL across every tool — it dedupes the WHOLE call. Use a distinct value per call, or omit unless you are actually retrying."
              },
              "caller": {
                "type": "object",
                "description": "Required self-reported provenance for this call. It identifies the agent host and model for activity/audit display only; it never grants permission. Use the exact model id when exposed by the host, otherwise the literal `unknown`.",
                "properties": {
                  "agent": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Calling agent or host product, for example ChatGPT, Codex, Claude Code, or Cursor."
                  },
                  "model": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Exact model identifier when known; use `unknown` when the host does not expose it. Never guess."
                  }
                },
                "required": [
                  "agent",
                  "model"
                ],
                "additionalProperties": false
              }
            },
            "required": [
              "space",
              "caller"
            ],
            "type": "object",
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "description": "v3 result. Success carries the named collections below plus `space`; a business failure carries `{ok:false, error:{code, message, retryable, next_action?}}` (spec §4). `content` remains available to text-oriented clients.",
            "additionalProperties": true
          }
        }
      ]
    },
    {
      "key": "memories",
      "title": "Memories",
      "access": "paired",
      "tools": [
        {
          "name": "list_memories",
          "title": "List memories",
          "description": "Use this when you need to read what the user captured on their phone, most recent first — the raw material behind briefings and coaching. Read-only and requires a paired iPhone. Metadata only unless you ask for full text; scope with `space` and narrow by time. Call `get_memory` for one memory's full text and extractions.",
          "readOnly": true,
          "destructive": false,
          "idempotent": true,
          "scopes": [
            "context:private"
          ],
          "inputParams": [
            "space",
            "query",
            "include_text",
            "from",
            "to",
            "limit",
            "cursor"
          ],
          "inputSchema": {
            "properties": {
              "space": {
                "type": "string",
                "description": "Space id or name. `shared` = the Shared Space (server-readable, available with Google sign-in alone); `personal`/`work` = the private built-ins on the paired iPhone; any other named private Space resolves by id or name. Omit to read across every Space you hold."
              },
              "query": {
                "type": "string",
                "maxLength": 256,
                "description": "Optional substring filter. For real search across everything, use `search_context`."
              },
              "include_text": {
                "type": "boolean",
                "default": false,
                "description": "Decrypt and inline each memory's text. Costly — leave false for discovery."
              },
              "from": {
                "type": "string",
                "description": "Only memories at or after this ISO 8601 instant."
              },
              "to": {
                "type": "string",
                "description": "Only memories before this ISO 8601 instant."
              },
              "limit": {
                "type": "integer",
                "minimum": 1,
                "maximum": 500,
                "default": 50,
                "description": "Maximum rows to return. Server-capped."
              },
              "cursor": {
                "type": "string",
                "description": "Opaque continuation from the previous call's `next_cursor`. Never parse it."
              },
              "caller": {
                "type": "object",
                "description": "Required self-reported provenance for this call. It identifies the agent host and model for activity/audit display only; it never grants permission. Use the exact model id when exposed by the host, otherwise the literal `unknown`.",
                "properties": {
                  "agent": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Calling agent or host product, for example ChatGPT, Codex, Claude Code, or Cursor."
                  },
                  "model": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Exact model identifier when known; use `unknown` when the host does not expose it. Never guess."
                  }
                },
                "required": [
                  "agent",
                  "model"
                ],
                "additionalProperties": false
              }
            },
            "type": "object",
            "additionalProperties": false,
            "required": [
              "caller"
            ]
          },
          "outputSchema": {
            "type": "object",
            "properties": {
              "memories": {
                "type": "array",
                "items": {
                  "type": "object",
                  "required": [
                    "id"
                  ],
                  "additionalProperties": true
                }
              },
              "next_cursor": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "space": {
                "type": [
                  "object",
                  "null"
                ]
              }
            },
            "required": [
              "memories"
            ],
            "additionalProperties": true
          }
        },
        {
          "name": "get_memory",
          "title": "Get one memory",
          "description": "Use this when you need to read one memory in full — raw text, the AI-enhanced version, extracted logs and people links, and a deep link that opens it on the phone. Read-only and requires a paired iPhone. Find ids with `list_memories` or `search_context`.",
          "readOnly": true,
          "destructive": false,
          "idempotent": true,
          "scopes": [
            "context:private"
          ],
          "inputParams": [
            "memory_id"
          ],
          "inputSchema": {
            "properties": {
              "memory_id": {
                "type": "string",
                "minLength": 1
              },
              "caller": {
                "type": "object",
                "description": "Required self-reported provenance for this call. It identifies the agent host and model for activity/audit display only; it never grants permission. Use the exact model id when exposed by the host, otherwise the literal `unknown`.",
                "properties": {
                  "agent": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Calling agent or host product, for example ChatGPT, Codex, Claude Code, or Cursor."
                  },
                  "model": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Exact model identifier when known; use `unknown` when the host does not expose it. Never guess."
                  }
                },
                "required": [
                  "agent",
                  "model"
                ],
                "additionalProperties": false
              }
            },
            "required": [
              "memory_id",
              "caller"
            ],
            "type": "object",
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "description": "v3 result. Success carries the named collections below plus `space`; a business failure carries `{ok:false, error:{code, message, retryable, next_action?}}` (spec §4). `content` remains available to text-oriented clients.",
            "additionalProperties": true
          }
        },
        {
          "name": "save_memories",
          "title": "Save memories and facts",
          "description": "Use this when you need to persist something the user told you beyond this session — a memory entry, or an atomic durable fact (a preference, a decision, biographical detail). Writes 1–20 private notes and/or facts into the user's own Context app: it never messages anyone, publishes anything, or deletes data, and the user can undo every one. Requires a paired iPhone and a `space`. Only save what you actually heard.",
          "readOnly": false,
          "destructive": false,
          "idempotent": false,
          "scopes": [
            "context:private"
          ],
          "inputParams": [
            "memories",
            "facts",
            "dedupe_key"
          ],
          "inputSchema": {
            "properties": {
              "memories": {
                "type": "array",
                "minItems": 1,
                "maxItems": 20,
                "items": {
                  "type": "object",
                  "properties": {
                    "text": {
                      "type": "string",
                      "maxLength": 5000
                    },
                    "title": {
                      "type": "string",
                      "maxLength": 300
                    },
                    "space": {
                      "type": "string",
                      "description": "Required. Destination Space: `shared` (Shared Space, the only destination until an iPhone is paired), `personal`/`work` (private built-ins), or a named private Space's id/name."
                    },
                    "created_at": {
                      "type": "string",
                      "description": "ISO 8601 timestamp. Defaults to now."
                    }
                  },
                  "required": [
                    "text",
                    "space"
                  ],
                  "additionalProperties": false
                }
              },
              "facts": {
                "type": "array",
                "minItems": 1,
                "maxItems": 10,
                "items": {
                  "type": "object",
                  "properties": {
                    "text": {
                      "type": "string",
                      "maxLength": 500,
                      "description": "One atomic durable fact, one sentence."
                    },
                    "space": {
                      "type": "string",
                      "description": "Required. Destination Space: `shared` (Shared Space, the only destination until an iPhone is paired), `personal`/`work` (private built-ins), or a named private Space's id/name."
                    },
                    "confidence": {
                      "type": "string",
                      "enum": [
                        "low",
                        "medium",
                        "high"
                      ],
                      "description": "Your certainty this is durable. Use `low`/`medium` for anything you inferred rather than heard."
                    },
                    "source_memory_ids": {
                      "type": "array",
                      "maxItems": 10,
                      "items": {
                        "type": "string"
                      },
                      "description": "Memory ids this fact was distilled from. Unknown ids are skipped."
                    }
                  },
                  "required": [
                    "text",
                    "space"
                  ],
                  "additionalProperties": false
                }
              },
              "dedupe_key": {
                "type": "string",
                "maxLength": 128,
                "description": "Optional idempotency key for retries. Per-account and GLOBAL across every tool — it dedupes the WHOLE call. Use a distinct value per call, or omit unless you are actually retrying."
              },
              "caller": {
                "type": "object",
                "description": "Required self-reported provenance for this call. It identifies the agent host and model for activity/audit display only; it never grants permission. Use the exact model id when exposed by the host, otherwise the literal `unknown`.",
                "properties": {
                  "agent": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Calling agent or host product, for example ChatGPT, Codex, Claude Code, or Cursor."
                  },
                  "model": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Exact model identifier when known; use `unknown` when the host does not expose it. Never guess."
                  }
                },
                "required": [
                  "agent",
                  "model"
                ],
                "additionalProperties": false
              }
            },
            "type": "object",
            "additionalProperties": false,
            "required": [
              "caller"
            ]
          },
          "outputSchema": {
            "type": "object",
            "description": "v3 result. Success carries the named collections below plus `space`; a business failure carries `{ok:false, error:{code, message, retryable, next_action?}}` (spec §4). `content` remains available to text-oriented clients.",
            "additionalProperties": true
          }
        },
        {
          "name": "delete_memories",
          "title": "Delete memories",
          "description": "Use this when you need to remove whole memories from the user's phone — their extracted logs and todos go with them. Destructive and irreversible on the device; requires pairing and delete permission, so confirm with the user first. Deleting is not the way to correct a fact: use `save_memories` for that.",
          "readOnly": false,
          "destructive": true,
          "idempotent": true,
          "scopes": [
            "context:private"
          ],
          "inputParams": [
            "memory_ids",
            "dedupe_key"
          ],
          "inputSchema": {
            "properties": {
              "memory_ids": {
                "type": "array",
                "minItems": 1,
                "maxItems": 20,
                "items": {
                  "type": "string"
                }
              },
              "dedupe_key": {
                "type": "string",
                "maxLength": 128,
                "description": "Optional idempotency key for retries. Per-account and GLOBAL across every tool — it dedupes the WHOLE call. Use a distinct value per call, or omit unless you are actually retrying."
              },
              "caller": {
                "type": "object",
                "description": "Required self-reported provenance for this call. It identifies the agent host and model for activity/audit display only; it never grants permission. Use the exact model id when exposed by the host, otherwise the literal `unknown`.",
                "properties": {
                  "agent": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Calling agent or host product, for example ChatGPT, Codex, Claude Code, or Cursor."
                  },
                  "model": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Exact model identifier when known; use `unknown` when the host does not expose it. Never guess."
                  }
                },
                "required": [
                  "agent",
                  "model"
                ],
                "additionalProperties": false
              }
            },
            "required": [
              "memory_ids",
              "caller"
            ],
            "type": "object",
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "description": "v3 result. Success carries the named collections below plus `space`; a business failure carries `{ok:false, error:{code, message, retryable, next_action?}}` (spec §4). `content` remains available to text-oriented clients.",
            "additionalProperties": true
          }
        }
      ]
    },
    {
      "key": "logs",
      "title": "Logs",
      "access": "paired",
      "tools": [
        {
          "name": "list_logs",
          "title": "List logged items",
          "description": "Use this when you need to read the user's atomic logged events — meals, workouts, expenses, or health readings (blood pressure, body metrics, HealthKit-mirrored items) — one row per event. Read-only, requires a paired iPhone. `kind: \"health\"` covers the voice-logged and HealthKit-mirrored fitness items; for the raw HealthKit firehose use `query_health_samples`. No roll-ups: you compute the totals. Row ids feed `delete_logs`.",
          "readOnly": true,
          "destructive": false,
          "idempotent": true,
          "scopes": [
            "context:private"
          ],
          "inputParams": [
            "kind",
            "space",
            "from",
            "to",
            "limit",
            "cursor"
          ],
          "inputSchema": {
            "properties": {
              "kind": {
                "type": "string",
                "enum": [
                  "meal",
                  "workout",
                  "expense",
                  "health",
                  "all"
                ],
                "default": "all",
                "description": "`meal` (calories), `workout`, `expense`, `health` (blood pressure, body metrics and HealthKit-mirrored fitness items), or `all`."
              },
              "space": {
                "type": "string",
                "description": "Space id or name. `shared` = the Shared Space (server-readable, available with Google sign-in alone); `personal`/`work` = the private built-ins on the paired iPhone; any other named private Space resolves by id or name. Omit to read across every Space you hold."
              },
              "from": {
                "type": "string",
                "description": "Only logs at or after this ISO 8601 instant."
              },
              "to": {
                "type": "string",
                "description": "Only logs before this ISO 8601 instant."
              },
              "limit": {
                "type": "integer",
                "minimum": 1,
                "maximum": 500,
                "default": 100,
                "description": "Maximum rows to return. Server-capped."
              },
              "cursor": {
                "type": "string",
                "description": "Opaque continuation from the previous call's `next_cursor`. Never parse it."
              },
              "caller": {
                "type": "object",
                "description": "Required self-reported provenance for this call. It identifies the agent host and model for activity/audit display only; it never grants permission. Use the exact model id when exposed by the host, otherwise the literal `unknown`.",
                "properties": {
                  "agent": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Calling agent or host product, for example ChatGPT, Codex, Claude Code, or Cursor."
                  },
                  "model": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Exact model identifier when known; use `unknown` when the host does not expose it. Never guess."
                  }
                },
                "required": [
                  "agent",
                  "model"
                ],
                "additionalProperties": false
              }
            },
            "type": "object",
            "additionalProperties": false,
            "required": [
              "caller"
            ]
          },
          "outputSchema": {
            "type": "object",
            "properties": {
              "logs": {
                "type": "array",
                "items": {
                  "type": "object",
                  "required": [
                    "kind"
                  ],
                  "additionalProperties": true
                }
              },
              "next_cursor": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "space": {
                "type": [
                  "object",
                  "null"
                ]
              }
            },
            "required": [
              "logs"
            ],
            "additionalProperties": true
          }
        },
        {
          "name": "log_meal",
          "title": "Send a meal plan",
          "description": "Use this when you need to give the user a meal to eat — meal prep, a restaurant order, a macro-targeted suggestion. Writes one planned meal to the paired iPhone and push-notifies it; completing it auto-logs the items to the calorie tracker and Apple Health, so per-item `kcal` must be your best estimate and macros matter. Requires pairing. Read it back later with `list_logs {kind: \"meal\"}`.",
          "readOnly": false,
          "destructive": false,
          "idempotent": false,
          "scopes": [
            "context:private"
          ],
          "inputParams": [
            "title",
            "items",
            "due_at",
            "notes",
            "space",
            "dedupe_key"
          ],
          "inputSchema": {
            "properties": {
              "title": {
                "type": "string",
                "maxLength": 500
              },
              "items": {
                "type": "array",
                "minItems": 1,
                "maxItems": 25,
                "items": {
                  "type": "object",
                  "properties": {
                    "name": {
                      "type": "string",
                      "maxLength": 200
                    },
                    "quantity": {
                      "type": "string",
                      "maxLength": 100
                    },
                    "kcal": {
                      "type": "number",
                      "minimum": 0
                    },
                    "protein_g": {
                      "type": "number",
                      "minimum": 0
                    },
                    "carbs_g": {
                      "type": "number",
                      "minimum": 0
                    },
                    "fat_g": {
                      "type": "number",
                      "minimum": 0
                    },
                    "sugar_g": {
                      "type": "number",
                      "minimum": 0
                    }
                  },
                  "required": [
                    "name",
                    "kcal"
                  ],
                  "additionalProperties": false
                }
              },
              "due_at": {
                "type": "string",
                "description": "Deadline as an ISO 8601 datetime (include the user's offset when known) or date (YYYY-MM-DD)."
              },
              "notes": {
                "type": "string",
                "maxLength": 2000
              },
              "space": {
                "type": "string",
                "description": "Destination Space. Meal data is inherently personal, so omitting this files it under Personal."
              },
              "dedupe_key": {
                "type": "string",
                "maxLength": 128,
                "description": "Optional idempotency key for retries. Per-account and GLOBAL across every tool — it dedupes the WHOLE call. Use a distinct value per call, or omit unless you are actually retrying."
              },
              "caller": {
                "type": "object",
                "description": "Required self-reported provenance for this call. It identifies the agent host and model for activity/audit display only; it never grants permission. Use the exact model id when exposed by the host, otherwise the literal `unknown`.",
                "properties": {
                  "agent": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Calling agent or host product, for example ChatGPT, Codex, Claude Code, or Cursor."
                  },
                  "model": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Exact model identifier when known; use `unknown` when the host does not expose it. Never guess."
                  }
                },
                "required": [
                  "agent",
                  "model"
                ],
                "additionalProperties": false
              }
            },
            "required": [
              "title",
              "items",
              "caller"
            ],
            "type": "object",
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "description": "v3 result. Success carries the named collections below plus `space`; a business failure carries `{ok:false, error:{code, message, retryable, next_action?}}` (spec §4). `content` remains available to text-oriented clients.",
            "additionalProperties": true
          }
        },
        {
          "name": "log_workout",
          "title": "Send a workout plan",
          "description": "Use this when you need to give the user exercise to do. Writes one workout plan to the paired iPhone and push-notifies it; it renders as a guided session and finishing it logs the completed exercises to the fitness tracker. Requires pairing. Give every exercise as much structure as you know — sets, reps, weight, kcal, a form cue, a specific tutorial link. Read it back with `list_logs {kind: \"workout\"}`.",
          "readOnly": false,
          "destructive": false,
          "idempotent": false,
          "scopes": [
            "context:private"
          ],
          "inputParams": [
            "title",
            "exercises",
            "due_at",
            "notes",
            "space",
            "dedupe_key"
          ],
          "inputSchema": {
            "properties": {
              "title": {
                "type": "string",
                "maxLength": 500
              },
              "exercises": {
                "type": "array",
                "minItems": 1,
                "maxItems": 25,
                "items": {
                  "type": "object",
                  "properties": {
                    "name": {
                      "type": "string",
                      "maxLength": 200
                    },
                    "sets": {
                      "type": "integer",
                      "minimum": 1
                    },
                    "reps": {
                      "type": "integer",
                      "minimum": 1
                    },
                    "weight": {
                      "type": "number",
                      "minimum": 0
                    },
                    "weight_unit": {
                      "type": "string",
                      "enum": [
                        "kg",
                        "lb"
                      ]
                    },
                    "duration_minutes": {
                      "type": "integer",
                      "minimum": 1
                    },
                    "muscle_groups": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "estimated_kcal_burn": {
                      "type": "number",
                      "minimum": 0
                    },
                    "note": {
                      "type": "string",
                      "maxLength": 500
                    },
                    "instructions_url": {
                      "type": "string",
                      "maxLength": 500
                    }
                  },
                  "required": [
                    "name"
                  ],
                  "additionalProperties": false
                }
              },
              "due_at": {
                "type": "string",
                "description": "Deadline as an ISO 8601 datetime (include the user's offset when known) or date (YYYY-MM-DD)."
              },
              "notes": {
                "type": "string",
                "maxLength": 2000
              },
              "space": {
                "type": "string",
                "description": "Destination Space. Health data is inherently personal, so omitting this files it under Personal."
              },
              "dedupe_key": {
                "type": "string",
                "maxLength": 128,
                "description": "Optional idempotency key for retries. Per-account and GLOBAL across every tool — it dedupes the WHOLE call. Use a distinct value per call, or omit unless you are actually retrying."
              },
              "caller": {
                "type": "object",
                "description": "Required self-reported provenance for this call. It identifies the agent host and model for activity/audit display only; it never grants permission. Use the exact model id when exposed by the host, otherwise the literal `unknown`.",
                "properties": {
                  "agent": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Calling agent or host product, for example ChatGPT, Codex, Claude Code, or Cursor."
                  },
                  "model": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Exact model identifier when known; use `unknown` when the host does not expose it. Never guess."
                  }
                },
                "required": [
                  "agent",
                  "model"
                ],
                "additionalProperties": false
              }
            },
            "required": [
              "title",
              "exercises",
              "caller"
            ],
            "type": "object",
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "description": "v3 result. Success carries the named collections below plus `space`; a business failure carries `{ok:false, error:{code, message, retryable, next_action?}}` (spec §4). `content` remains available to text-oriented clients.",
            "additionalProperties": true
          }
        },
        {
          "name": "delete_logs",
          "title": "Delete logged items",
          "description": "Use this when you need to remove logged rows that are wrong — a mis-transcribed meal, a duplicated expense. Destructive: requires pairing and delete permission. Address rows exactly as `list_logs` returned them; omit `item_id` to delete a whole log group. Deleting a group's last item removes the group.",
          "readOnly": false,
          "destructive": true,
          "idempotent": true,
          "scopes": [
            "context:private"
          ],
          "inputParams": [
            "logs",
            "dedupe_key"
          ],
          "inputSchema": {
            "properties": {
              "logs": {
                "type": "array",
                "minItems": 1,
                "maxItems": 20,
                "items": {
                  "type": "object",
                  "properties": {
                    "memory_id": {
                      "type": "string",
                      "description": "The memory that owns this log (from `list_logs`)."
                    },
                    "log_id": {
                      "type": "string"
                    },
                    "item_id": {
                      "type": "string",
                      "description": "One row inside the log group. Omit to delete the whole group."
                    }
                  },
                  "required": [
                    "memory_id",
                    "log_id"
                  ],
                  "additionalProperties": false
                }
              },
              "dedupe_key": {
                "type": "string",
                "maxLength": 128,
                "description": "Optional idempotency key for retries. Per-account and GLOBAL across every tool — it dedupes the WHOLE call. Use a distinct value per call, or omit unless you are actually retrying."
              },
              "caller": {
                "type": "object",
                "description": "Required self-reported provenance for this call. It identifies the agent host and model for activity/audit display only; it never grants permission. Use the exact model id when exposed by the host, otherwise the literal `unknown`.",
                "properties": {
                  "agent": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Calling agent or host product, for example ChatGPT, Codex, Claude Code, or Cursor."
                  },
                  "model": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Exact model identifier when known; use `unknown` when the host does not expose it. Never guess."
                  }
                },
                "required": [
                  "agent",
                  "model"
                ],
                "additionalProperties": false
              }
            },
            "required": [
              "logs",
              "caller"
            ],
            "type": "object",
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "description": "v3 result. Success carries the named collections below plus `space`; a business failure carries `{ok:false, error:{code, message, retryable, next_action?}}` (spec §4). `content` remains available to text-oriented clients.",
            "additionalProperties": true
          }
        }
      ]
    },
    {
      "key": "people",
      "title": "People",
      "access": "paired",
      "tools": [
        {
          "name": "list_people",
          "title": "List people",
          "description": "Use this when you need to read the roster the user opted to share — names, aliases, organizations. Read-only, requires a paired iPhone. Address books get large: pass `fields` for whole-roster scans (duplicate hunting) so full profiles do not flood your context, and page with `limit`/`cursor`. Call `get_person` for one full profile.",
          "readOnly": true,
          "destructive": false,
          "idempotent": true,
          "scopes": [
            "context:private"
          ],
          "inputParams": [
            "query",
            "fields",
            "limit",
            "cursor"
          ],
          "inputSchema": {
            "properties": {
              "query": {
                "type": "string",
                "description": "Name, alias, or organization substring."
              },
              "fields": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "Projection — return only these fields per person (`id` is always included). Use it for whole-roster scans."
              },
              "limit": {
                "type": "integer",
                "minimum": 1,
                "maximum": 1000,
                "default": 50,
                "description": "Maximum rows to return. Server-capped."
              },
              "cursor": {
                "type": "string",
                "description": "Opaque continuation from the previous call's `next_cursor`. Never parse it."
              },
              "caller": {
                "type": "object",
                "description": "Required self-reported provenance for this call. It identifies the agent host and model for activity/audit display only; it never grants permission. Use the exact model id when exposed by the host, otherwise the literal `unknown`.",
                "properties": {
                  "agent": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Calling agent or host product, for example ChatGPT, Codex, Claude Code, or Cursor."
                  },
                  "model": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Exact model identifier when known; use `unknown` when the host does not expose it. Never guess."
                  }
                },
                "required": [
                  "agent",
                  "model"
                ],
                "additionalProperties": false
              }
            },
            "type": "object",
            "additionalProperties": false,
            "required": [
              "caller"
            ]
          },
          "outputSchema": {
            "type": "object",
            "properties": {
              "people": {
                "type": "array",
                "items": {
                  "type": "object",
                  "required": [
                    "id"
                  ],
                  "additionalProperties": true
                }
              },
              "next_cursor": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "space": {
                "type": [
                  "object",
                  "null"
                ]
              }
            },
            "required": [
              "people"
            ],
            "additionalProperties": true
          }
        },
        {
          "name": "get_person",
          "title": "Get one person",
          "description": "Use this when you need to read everything Context knows about one person — the profile the user synced, and optionally the memories linked to them. Read-only, requires a paired iPhone; suggested-but-unconfirmed links are excluded. Set `include_memories: true` for the relationship history behind a briefing.",
          "readOnly": true,
          "destructive": false,
          "idempotent": true,
          "scopes": [
            "context:private"
          ],
          "inputParams": [
            "person_id",
            "include_memories",
            "memories_limit"
          ],
          "inputSchema": {
            "properties": {
              "person_id": {
                "type": "string",
                "minLength": 1
              },
              "include_memories": {
                "type": "boolean",
                "default": false,
                "description": "Also return the confirmed memories linked to this person."
              },
              "memories_limit": {
                "type": "integer",
                "minimum": 1,
                "maximum": 100
              },
              "caller": {
                "type": "object",
                "description": "Required self-reported provenance for this call. It identifies the agent host and model for activity/audit display only; it never grants permission. Use the exact model id when exposed by the host, otherwise the literal `unknown`.",
                "properties": {
                  "agent": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Calling agent or host product, for example ChatGPT, Codex, Claude Code, or Cursor."
                  },
                  "model": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Exact model identifier when known; use `unknown` when the host does not expose it. Never guess."
                  }
                },
                "required": [
                  "agent",
                  "model"
                ],
                "additionalProperties": false
              }
            },
            "required": [
              "person_id",
              "caller"
            ],
            "type": "object",
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "description": "v3 result. Success carries the named collections below plus `space`; a business failure carries `{ok:false, error:{code, message, retryable, next_action?}}` (spec §4). `content` remains available to text-oriented clients.",
            "additionalProperties": true
          }
        },
        {
          "name": "create_people",
          "title": "Create person profiles",
          "description": "Use this when you need to create a profile for someone the user talks about who has none. Writes 1–20 app-created profiles to the paired iPhone (not linked to system Contacts), so it requires pairing. Check `list_people` first — creating a profile that duplicates a contact is worse than none; `merge_people` is the fix when it happens.",
          "readOnly": false,
          "destructive": false,
          "idempotent": false,
          "scopes": [
            "context:private"
          ],
          "inputParams": [
            "people",
            "dedupe_key"
          ],
          "inputSchema": {
            "properties": {
              "people": {
                "type": "array",
                "minItems": 1,
                "maxItems": 20,
                "items": {
                  "type": "object",
                  "properties": {
                    "display_name": {
                      "type": "string",
                      "maxLength": 200
                    },
                    "given_name": {
                      "type": "string",
                      "maxLength": 200
                    },
                    "family_name": {
                      "type": "string",
                      "maxLength": 200
                    },
                    "nickname": {
                      "type": "string",
                      "maxLength": 200
                    },
                    "organization_name": {
                      "type": "string",
                      "maxLength": 300
                    },
                    "job_title": {
                      "type": "string",
                      "maxLength": 300
                    },
                    "department_name": {
                      "type": "string",
                      "maxLength": 300
                    },
                    "phone_numbers": {
                      "type": "array",
                      "maxItems": 10,
                      "items": {
                        "type": "string",
                        "maxLength": 50
                      }
                    },
                    "email_addresses": {
                      "type": "array",
                      "maxItems": 10,
                      "items": {
                        "type": "string",
                        "maxLength": 300
                      }
                    }
                  },
                  "required": [
                    "display_name"
                  ],
                  "additionalProperties": false
                }
              },
              "dedupe_key": {
                "type": "string",
                "maxLength": 128,
                "description": "Optional idempotency key for retries. Per-account and GLOBAL across every tool — it dedupes the WHOLE call. Use a distinct value per call, or omit unless you are actually retrying."
              },
              "caller": {
                "type": "object",
                "description": "Required self-reported provenance for this call. It identifies the agent host and model for activity/audit display only; it never grants permission. Use the exact model id when exposed by the host, otherwise the literal `unknown`.",
                "properties": {
                  "agent": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Calling agent or host product, for example ChatGPT, Codex, Claude Code, or Cursor."
                  },
                  "model": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Exact model identifier when known; use `unknown` when the host does not expose it. Never guess."
                  }
                },
                "required": [
                  "agent",
                  "model"
                ],
                "additionalProperties": false
              }
            },
            "required": [
              "people",
              "caller"
            ],
            "type": "object",
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "description": "v3 result. Success carries the named collections below plus `space`; a business failure carries `{ok:false, error:{code, message, retryable, next_action?}}` (spec §4). `content` remains available to text-oriented clients.",
            "additionalProperties": true
          }
        },
        {
          "name": "update_people",
          "title": "Update people",
          "description": "Use this when you need to record something you learned about people the user already has profiles for — contact-card fields, or `remembered_facts` for what the user TOLD you. Writes 1–20 profiles on the paired iPhone; requires pairing. Your writes are stamped with your caller identity and capped at externally-asserted confidence: they can fill a gap but never overwrite what the user stated themselves. Only save what you actually heard.",
          "readOnly": false,
          "destructive": false,
          "idempotent": false,
          "scopes": [
            "context:private"
          ],
          "inputParams": [
            "people",
            "dedupe_key"
          ],
          "inputSchema": {
            "properties": {
              "people": {
                "type": "array",
                "minItems": 1,
                "maxItems": 20,
                "items": {
                  "type": "object",
                  "properties": {
                    "person_id": {
                      "type": "string",
                      "minLength": 1
                    },
                    "display_name": {
                      "type": "string",
                      "maxLength": 200
                    },
                    "given_name": {
                      "type": "string",
                      "maxLength": 200
                    },
                    "family_name": {
                      "type": "string",
                      "maxLength": 200
                    },
                    "nickname": {
                      "type": "string",
                      "maxLength": 200
                    },
                    "organization_name": {
                      "type": "string",
                      "maxLength": 300
                    },
                    "job_title": {
                      "type": "string",
                      "maxLength": 300
                    },
                    "department_name": {
                      "type": "string",
                      "maxLength": 300
                    },
                    "phone_numbers": {
                      "type": "array",
                      "maxItems": 10,
                      "items": {
                        "type": "string",
                        "maxLength": 50
                      }
                    },
                    "email_addresses": {
                      "type": "array",
                      "maxItems": 10,
                      "items": {
                        "type": "string",
                        "maxLength": 300
                      }
                    },
                    "remembered_facts": {
                      "type": "array",
                      "maxItems": 10,
                      "items": {
                        "type": "string",
                        "maxLength": 300
                      },
                      "description": "Durable free-text facts the user told you — 'has two kids', 'met at the Bangalore off-site'. One sentence each."
                    }
                  },
                  "required": [
                    "person_id"
                  ],
                  "additionalProperties": false
                }
              },
              "dedupe_key": {
                "type": "string",
                "maxLength": 128,
                "description": "Optional idempotency key for retries. Per-account and GLOBAL across every tool — it dedupes the WHOLE call. Use a distinct value per call, or omit unless you are actually retrying."
              },
              "caller": {
                "type": "object",
                "description": "Required self-reported provenance for this call. It identifies the agent host and model for activity/audit display only; it never grants permission. Use the exact model id when exposed by the host, otherwise the literal `unknown`.",
                "properties": {
                  "agent": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Calling agent or host product, for example ChatGPT, Codex, Claude Code, or Cursor."
                  },
                  "model": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Exact model identifier when known; use `unknown` when the host does not expose it. Never guess."
                  }
                },
                "required": [
                  "agent",
                  "model"
                ],
                "additionalProperties": false
              }
            },
            "required": [
              "people",
              "caller"
            ],
            "type": "object",
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "description": "v3 result. Success carries the named collections below plus `space`; a business failure carries `{ok:false, error:{code, message, retryable, next_action?}}` (spec §4). `content` remains available to text-oriented clients.",
            "additionalProperties": true
          }
        },
        {
          "name": "delete_people",
          "title": "Delete person profiles",
          "description": "Use this when you need to remove app-created or junk profiles that should not exist at all — and ONLY those. Destructive: requires pairing and delete permission, and it is usually the WRONG tool for duplicates — a profile backed by an iOS contact is re-created on the next import, so deletion does not stick. Use `merge_people` for duplicates. The user's own \"Me\" profile can never be deleted.",
          "readOnly": false,
          "destructive": true,
          "idempotent": true,
          "scopes": [
            "context:private"
          ],
          "inputParams": [
            "person_ids",
            "dedupe_key"
          ],
          "inputSchema": {
            "properties": {
              "person_ids": {
                "type": "array",
                "minItems": 1,
                "maxItems": 20,
                "items": {
                  "type": "string"
                }
              },
              "dedupe_key": {
                "type": "string",
                "maxLength": 128,
                "description": "Optional idempotency key for retries. Per-account and GLOBAL across every tool — it dedupes the WHOLE call. Use a distinct value per call, or omit unless you are actually retrying."
              },
              "caller": {
                "type": "object",
                "description": "Required self-reported provenance for this call. It identifies the agent host and model for activity/audit display only; it never grants permission. Use the exact model id when exposed by the host, otherwise the literal `unknown`.",
                "properties": {
                  "agent": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Calling agent or host product, for example ChatGPT, Codex, Claude Code, or Cursor."
                  },
                  "model": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Exact model identifier when known; use `unknown` when the host does not expose it. Never guess."
                  }
                },
                "required": [
                  "agent",
                  "model"
                ],
                "additionalProperties": false
              }
            },
            "required": [
              "person_ids",
              "caller"
            ],
            "type": "object",
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "description": "v3 result. Success carries the named collections below plus `space`; a business failure carries `{ok:false, error:{code, message, retryable, next_action?}}` (spec §4). `content` remains available to text-oriented clients.",
            "additionalProperties": true
          }
        },
        {
          "name": "merge_people",
          "title": "Merge duplicate people",
          "description": "Use this when you need to fold several profiles of the same real person into one — this is the durable fix for duplicate contacts, unlike deletion. Writes: phone numbers, emails, facts and links are unioned into the survivor you pick, and the user can undo it in the app. Requires pairing and write (not delete) permission. Find the clusters yourself from `list_people`, and confirm anything you are unsure about with the user first.",
          "readOnly": false,
          "destructive": false,
          "idempotent": false,
          "scopes": [
            "context:private"
          ],
          "inputParams": [
            "merges",
            "dedupe_key"
          ],
          "inputSchema": {
            "properties": {
              "merges": {
                "type": "array",
                "minItems": 1,
                "maxItems": 20,
                "items": {
                  "type": "object",
                  "properties": {
                    "keep_person_id": {
                      "type": "string",
                      "description": "The profile that survives and absorbs the others — prefer the richest, most correct one."
                    },
                    "merge_person_ids": {
                      "type": "array",
                      "minItems": 1,
                      "maxItems": 20,
                      "items": {
                        "type": "string"
                      }
                    }
                  },
                  "required": [
                    "keep_person_id",
                    "merge_person_ids"
                  ],
                  "additionalProperties": false
                }
              },
              "dedupe_key": {
                "type": "string",
                "maxLength": 128,
                "description": "Optional idempotency key for retries. Per-account and GLOBAL across every tool — it dedupes the WHOLE call. Use a distinct value per call, or omit unless you are actually retrying."
              },
              "caller": {
                "type": "object",
                "description": "Required self-reported provenance for this call. It identifies the agent host and model for activity/audit display only; it never grants permission. Use the exact model id when exposed by the host, otherwise the literal `unknown`.",
                "properties": {
                  "agent": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Calling agent or host product, for example ChatGPT, Codex, Claude Code, or Cursor."
                  },
                  "model": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Exact model identifier when known; use `unknown` when the host does not expose it. Never guess."
                  }
                },
                "required": [
                  "agent",
                  "model"
                ],
                "additionalProperties": false
              }
            },
            "required": [
              "merges",
              "caller"
            ],
            "type": "object",
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "description": "v3 result. Success carries the named collections below plus `space`; a business failure carries `{ok:false, error:{code, message, retryable, next_action?}}` (spec §4). `content` remains available to text-oriented clients.",
            "additionalProperties": true
          }
        }
      ]
    },
    {
      "key": "health",
      "title": "Health",
      "access": "paired",
      "tools": [
        {
          "name": "query_health_samples",
          "title": "Query HealthKit samples",
          "description": "Use this when you need to read raw HealthKit rows the user opted into agent collection — steps, heart rate, sleep, HRV, glucose. Read-only, requires a paired iPhone. Omit `type` and it returns the available types with their sample counts, so this is also the discovery call; then pass one `type` plus a range of at most 31 days. For totals and averages use `summarize_health` instead of pulling every row.",
          "readOnly": true,
          "destructive": false,
          "idempotent": true,
          "scopes": [
            "context:private"
          ],
          "inputParams": [
            "type",
            "from",
            "to",
            "source",
            "unit_policy",
            "limit",
            "cursor"
          ],
          "inputSchema": {
            "properties": {
              "type": {
                "type": "string",
                "minLength": 1,
                "description": "HealthKit type identifier, for example `heartRate`, `stepCount`, `sleepAnalysis`. Omit to discover which types have data."
              },
              "from": {
                "type": "string",
                "description": "Inclusive range start, ISO 8601."
              },
              "to": {
                "type": "string",
                "description": "Exclusive range end, ISO 8601. At most 31 days."
              },
              "source": {
                "type": "string",
                "description": "Filter by source app or device name (substring)."
              },
              "unit_policy": {
                "type": "string",
                "enum": [
                  "canonical",
                  "source"
                ],
                "default": "canonical",
                "description": "Convert to the canonical HealthKit unit, or preserve the uploaded unit."
              },
              "limit": {
                "type": "integer",
                "minimum": 1,
                "maximum": 500,
                "default": 100,
                "description": "Maximum rows to return. Server-capped."
              },
              "cursor": {
                "type": "string",
                "description": "Opaque continuation from the previous call's `next_cursor`. Never parse it."
              },
              "caller": {
                "type": "object",
                "description": "Required self-reported provenance for this call. It identifies the agent host and model for activity/audit display only; it never grants permission. Use the exact model id when exposed by the host, otherwise the literal `unknown`.",
                "properties": {
                  "agent": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Calling agent or host product, for example ChatGPT, Codex, Claude Code, or Cursor."
                  },
                  "model": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Exact model identifier when known; use `unknown` when the host does not expose it. Never guess."
                  }
                },
                "required": [
                  "agent",
                  "model"
                ],
                "additionalProperties": false
              }
            },
            "type": "object",
            "additionalProperties": false,
            "required": [
              "caller"
            ]
          },
          "outputSchema": {
            "type": "object",
            "properties": {
              "samples": {
                "type": "array",
                "items": {
                  "type": "object"
                }
              },
              "types": {
                "type": "array",
                "items": {
                  "type": "object"
                }
              },
              "next_cursor": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "partial": {
                "type": "boolean"
              },
              "coverage": {
                "type": "object"
              }
            },
            "additionalProperties": true
          }
        },
        {
          "name": "summarize_health",
          "title": "Summarize health samples",
          "description": "Use this when you need to answer a question about a trend or a total rather than individual readings — daily steps, weekly sleep, monthly weight. Read-only, requires a paired iPhone. Aggregates one type into timezone-aware buckets with units, counts, coverage and partial markers; hourly ranges cap at 31 days, others at 366. Raw rows stay available through `query_health_samples` for verification.",
          "readOnly": true,
          "destructive": false,
          "idempotent": true,
          "scopes": [
            "context:private"
          ],
          "inputParams": [
            "type",
            "from",
            "to",
            "bucket",
            "timezone",
            "statistic",
            "source",
            "limit",
            "cursor"
          ],
          "inputSchema": {
            "properties": {
              "type": {
                "type": "string",
                "minLength": 1
              },
              "from": {
                "type": "string",
                "description": "Inclusive range start, ISO 8601."
              },
              "to": {
                "type": "string",
                "description": "Exclusive range end, ISO 8601."
              },
              "bucket": {
                "type": "string",
                "enum": [
                  "hour",
                  "day",
                  "week",
                  "month"
                ]
              },
              "timezone": {
                "type": "string",
                "description": "IANA timezone for bucket boundaries, for example `Asia/Singapore`. Weeks start Monday."
              },
              "statistic": {
                "type": "string",
                "enum": [
                  "sum",
                  "average",
                  "min",
                  "max",
                  "latest",
                  "count",
                  "duration"
                ],
                "description": "Validated per type — an unsupported combination is rejected rather than guessed. Defaults per the HealthKit type registry."
              },
              "source": {
                "type": "string",
                "description": "Case-insensitive source app or device substring."
              },
              "limit": {
                "type": "integer",
                "minimum": 1,
                "maximum": 366,
                "default": 100,
                "description": "Maximum rows to return. Server-capped."
              },
              "cursor": {
                "type": "string",
                "description": "Opaque continuation from the previous call's `next_cursor`. Never parse it."
              },
              "caller": {
                "type": "object",
                "description": "Required self-reported provenance for this call. It identifies the agent host and model for activity/audit display only; it never grants permission. Use the exact model id when exposed by the host, otherwise the literal `unknown`.",
                "properties": {
                  "agent": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Calling agent or host product, for example ChatGPT, Codex, Claude Code, or Cursor."
                  },
                  "model": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Exact model identifier when known; use `unknown` when the host does not expose it. Never guess."
                  }
                },
                "required": [
                  "agent",
                  "model"
                ],
                "additionalProperties": false
              }
            },
            "required": [
              "type",
              "from",
              "to",
              "bucket",
              "timezone",
              "caller"
            ],
            "type": "object",
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "properties": {
              "buckets": {
                "type": "array",
                "items": {
                  "type": "object"
                }
              },
              "next_cursor": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "partial": {
                "type": "boolean"
              },
              "coverage": {
                "type": "object"
              },
              "statistic": {
                "type": "string"
              },
              "unit": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "additionalProperties": true
          }
        }
      ]
    },
    {
      "key": "calendar",
      "title": "Calendar",
      "access": "paired",
      "tools": [
        {
          "name": "list_calendar_events",
          "title": "List calendar events",
          "description": "Use this when you need to read the user's schedule — what a day held, who was in a meeting, what is coming up. Read-only, requires a paired iPhone; covers the synced window (roughly the past 60 days and next 30), Apple and Google de-duplicated. Cheap, like `list_issues`: call it liberally. Each row links the memories, Artifacts, Issues and people attached to that event.",
          "readOnly": true,
          "destructive": false,
          "idempotent": true,
          "scopes": [
            "context:private"
          ],
          "inputParams": [
            "from",
            "to",
            "attendee",
            "person_id",
            "query",
            "include_cancelled",
            "limit",
            "cursor"
          ],
          "inputSchema": {
            "properties": {
              "from": {
                "type": "string",
                "description": "Window start, ISO 8601. An event counts when it overlaps the window."
              },
              "to": {
                "type": "string",
                "description": "Window end, ISO 8601, exclusive."
              },
              "attendee": {
                "type": "string",
                "description": "Attendee or organizer email (exact, case-insensitive) or a name substring."
              },
              "person_id": {
                "type": "string",
                "description": "Only events this person attended."
              },
              "query": {
                "type": "string",
                "description": "Case-insensitive substring over title, location and description."
              },
              "include_cancelled": {
                "type": "boolean",
                "default": false
              },
              "limit": {
                "type": "integer",
                "minimum": 1,
                "maximum": 200,
                "default": 50,
                "description": "Maximum rows to return. Server-capped."
              },
              "cursor": {
                "type": "string",
                "description": "Opaque continuation from the previous call's `next_cursor`. Never parse it."
              },
              "caller": {
                "type": "object",
                "description": "Required self-reported provenance for this call. It identifies the agent host and model for activity/audit display only; it never grants permission. Use the exact model id when exposed by the host, otherwise the literal `unknown`.",
                "properties": {
                  "agent": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Calling agent or host product, for example ChatGPT, Codex, Claude Code, or Cursor."
                  },
                  "model": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Exact model identifier when known; use `unknown` when the host does not expose it. Never guess."
                  }
                },
                "required": [
                  "agent",
                  "model"
                ],
                "additionalProperties": false
              }
            },
            "type": "object",
            "additionalProperties": false,
            "required": [
              "caller"
            ]
          },
          "outputSchema": {
            "type": "object",
            "properties": {
              "events": {
                "type": "array",
                "items": {
                  "type": "object",
                  "required": [
                    "id"
                  ],
                  "additionalProperties": true
                }
              },
              "next_cursor": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "space": {
                "type": [
                  "object",
                  "null"
                ]
              }
            },
            "required": [
              "events"
            ],
            "additionalProperties": true
          }
        },
        {
          "name": "get_calendar_event",
          "title": "Get one calendar event",
          "description": "Use this when you need to read one meeting in full — attendees and which resolve to people, organizer, location, join link, and the memories, Artifacts and Issues attached to it. Read-only, requires a paired iPhone. Find ids with `list_calendar_events`.",
          "readOnly": true,
          "destructive": false,
          "idempotent": true,
          "scopes": [
            "context:private"
          ],
          "inputParams": [
            "event_id"
          ],
          "inputSchema": {
            "properties": {
              "event_id": {
                "type": "string",
                "minLength": 1
              },
              "caller": {
                "type": "object",
                "description": "Required self-reported provenance for this call. It identifies the agent host and model for activity/audit display only; it never grants permission. Use the exact model id when exposed by the host, otherwise the literal `unknown`.",
                "properties": {
                  "agent": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Calling agent or host product, for example ChatGPT, Codex, Claude Code, or Cursor."
                  },
                  "model": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Exact model identifier when known; use `unknown` when the host does not expose it. Never guess."
                  }
                },
                "required": [
                  "agent",
                  "model"
                ],
                "additionalProperties": false
              }
            },
            "required": [
              "event_id",
              "caller"
            ],
            "type": "object",
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "description": "v3 result. Success carries the named collections below plus `space`; a business failure carries `{ok:false, error:{code, message, retryable, next_action?}}` (spec §4). `content` remains available to text-oriented clients.",
            "additionalProperties": true
          }
        }
      ]
    },
    {
      "key": "skills",
      "title": "Skills",
      "access": "paired",
      "tools": [
        {
          "name": "list_skills",
          "title": "List the user's stored skills",
          "description": "Use this when you need to find the playbooks the user or an agent stored on the phone — how THIS user wants a recurring job done. Read-only, requires a paired iPhone. These are the user's own skill documents, not the published Context skill that `start_context` reports. Call `get_skill` for the full markdown.",
          "readOnly": true,
          "destructive": false,
          "idempotent": true,
          "scopes": [
            "context:private"
          ],
          "inputParams": [
            "space",
            "limit",
            "cursor"
          ],
          "inputSchema": {
            "properties": {
              "space": {
                "type": "string",
                "description": "Space id or name. `shared` = the Shared Space (server-readable, available with Google sign-in alone); `personal`/`work` = the private built-ins on the paired iPhone; any other named private Space resolves by id or name. Omit to read across every Space you hold."
              },
              "limit": {
                "type": "integer",
                "minimum": 1,
                "maximum": 200,
                "default": 50,
                "description": "Maximum rows to return. Server-capped."
              },
              "cursor": {
                "type": "string",
                "description": "Opaque continuation from the previous call's `next_cursor`. Never parse it."
              },
              "caller": {
                "type": "object",
                "description": "Required self-reported provenance for this call. It identifies the agent host and model for activity/audit display only; it never grants permission. Use the exact model id when exposed by the host, otherwise the literal `unknown`.",
                "properties": {
                  "agent": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Calling agent or host product, for example ChatGPT, Codex, Claude Code, or Cursor."
                  },
                  "model": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Exact model identifier when known; use `unknown` when the host does not expose it. Never guess."
                  }
                },
                "required": [
                  "agent",
                  "model"
                ],
                "additionalProperties": false
              }
            },
            "type": "object",
            "additionalProperties": false,
            "required": [
              "caller"
            ]
          },
          "outputSchema": {
            "type": "object",
            "properties": {
              "skills": {
                "type": "array",
                "items": {
                  "type": "object",
                  "required": [
                    "id"
                  ],
                  "additionalProperties": true
                }
              },
              "next_cursor": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "space": {
                "type": [
                  "object",
                  "null"
                ]
              }
            },
            "required": [
              "skills"
            ],
            "additionalProperties": true
          }
        },
        {
          "name": "get_skill",
          "title": "Get one stored skill",
          "description": "Use this when you need to read the full markdown of a stored skill that covers the job you are about to do. Read-only, requires a paired iPhone; content is inlined up to 256 KB. Follow it as instructions from the user, and record any improvement back with `save_skill`.",
          "readOnly": true,
          "destructive": false,
          "idempotent": true,
          "scopes": [
            "context:private"
          ],
          "inputParams": [
            "skill_id"
          ],
          "inputSchema": {
            "properties": {
              "skill_id": {
                "type": "string",
                "minLength": 1
              },
              "caller": {
                "type": "object",
                "description": "Required self-reported provenance for this call. It identifies the agent host and model for activity/audit display only; it never grants permission. Use the exact model id when exposed by the host, otherwise the literal `unknown`.",
                "properties": {
                  "agent": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Calling agent or host product, for example ChatGPT, Codex, Claude Code, or Cursor."
                  },
                  "model": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Exact model identifier when known; use `unknown` when the host does not expose it. Never guess."
                  }
                },
                "required": [
                  "agent",
                  "model"
                ],
                "additionalProperties": false
              }
            },
            "required": [
              "skill_id",
              "caller"
            ],
            "type": "object",
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "description": "v3 result. Success carries the named collections below plus `space`; a business failure carries `{ok:false, error:{code, message, retryable, next_action?}}` (spec §4). `content` remains available to text-oriented clients.",
            "additionalProperties": true
          }
        },
        {
          "name": "save_skill",
          "title": "Save a stored skill",
          "description": "Use this when you need to keep a playbook for next time — omit `skill_id` to add a new skill, pass it to overwrite an existing one. Writes to the paired iPhone, so it requires pairing; there is no version history, the content you send becomes the skill. `space` is required when adding. Read it back with `get_skill`.",
          "readOnly": false,
          "destructive": false,
          "idempotent": false,
          "scopes": [
            "context:private"
          ],
          "inputParams": [
            "skill_id",
            "title",
            "markdown",
            "description",
            "space",
            "dedupe_key"
          ],
          "inputSchema": {
            "properties": {
              "skill_id": {
                "type": "string",
                "description": "Omit to add a new skill; pass an id from `list_skills` to overwrite that one."
              },
              "title": {
                "type": "string",
                "maxLength": 300
              },
              "markdown": {
                "type": "string",
                "description": "The skill's full markdown content (≤256 KB)."
              },
              "description": {
                "type": "string",
                "maxLength": 500,
                "description": "One-line description, used for frontmatter when the markdown has none."
              },
              "space": {
                "type": "string",
                "description": "Required when adding a new skill."
              },
              "dedupe_key": {
                "type": "string",
                "maxLength": 128,
                "description": "Optional idempotency key for retries. Per-account and GLOBAL across every tool — it dedupes the WHOLE call. Use a distinct value per call, or omit unless you are actually retrying."
              },
              "caller": {
                "type": "object",
                "description": "Required self-reported provenance for this call. It identifies the agent host and model for activity/audit display only; it never grants permission. Use the exact model id when exposed by the host, otherwise the literal `unknown`.",
                "properties": {
                  "agent": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Calling agent or host product, for example ChatGPT, Codex, Claude Code, or Cursor."
                  },
                  "model": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Exact model identifier when known; use `unknown` when the host does not expose it. Never guess."
                  }
                },
                "required": [
                  "agent",
                  "model"
                ],
                "additionalProperties": false
              }
            },
            "type": "object",
            "additionalProperties": false,
            "required": [
              "caller"
            ]
          },
          "outputSchema": {
            "type": "object",
            "description": "v3 result. Success carries the named collections below plus `space`; a business failure carries `{ok:false, error:{code, message, retryable, next_action?}}` (spec §4). `content` remains available to text-oriented clients.",
            "additionalProperties": true
          }
        }
      ]
    },
    {
      "key": "content",
      "title": "Content",
      "access": "paired",
      "tools": [
        {
          "name": "request_content",
          "title": "Request private content from the phone",
          "description": "Use this when you need to fetch device-held content that routine sync deliberately does not carry — a document body, a contact field, a health sample. Writes a durable, metadata-addressed request; the phone fulfils it only for an already-authorized collection, and an offline phone leaves it pending rather than failing. Requires pairing. Poll `get_content_request` for the download URL.",
          "readOnly": false,
          "destructive": false,
          "idempotent": false,
          "scopes": [
            "context:private"
          ],
          "inputParams": [
            "resource_kind",
            "resource_id",
            "selector",
            "content_version"
          ],
          "inputSchema": {
            "properties": {
              "resource_kind": {
                "type": "string",
                "enum": [
                  "artifact",
                  "memory",
                  "log",
                  "person"
                ]
              },
              "resource_id": {
                "type": "string",
                "minLength": 1,
                "maxLength": 300
              },
              "selector": {
                "type": "object",
                "description": "Optional narrowing selector for the resource.",
                "additionalProperties": true
              },
              "content_version": {
                "type": "string",
                "maxLength": 200
              },
              "caller": {
                "type": "object",
                "description": "Required self-reported provenance for this call. It identifies the agent host and model for activity/audit display only; it never grants permission. Use the exact model id when exposed by the host, otherwise the literal `unknown`.",
                "properties": {
                  "agent": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Calling agent or host product, for example ChatGPT, Codex, Claude Code, or Cursor."
                  },
                  "model": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Exact model identifier when known; use `unknown` when the host does not expose it. Never guess."
                  }
                },
                "required": [
                  "agent",
                  "model"
                ],
                "additionalProperties": false
              }
            },
            "required": [
              "resource_kind",
              "resource_id",
              "caller"
            ],
            "type": "object",
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "description": "v3 result. Success carries the named collections below plus `space`; a business failure carries `{ok:false, error:{code, message, retryable, next_action?}}` (spec §4). `content` remains available to text-oriented clients.",
            "additionalProperties": true
          }
        },
        {
          "name": "get_content_request",
          "title": "Inspect a content request",
          "description": "Use this when you need to know whether the phone has answered a `request_content` you are waiting on. Read-only, requires a paired iPhone. Reports queued, delivered, ready, failed or expired; ready content is available through an authorized URL for fifteen minutes. `queued` means the phone has not been reachable yet — do not tell the user it failed.",
          "readOnly": true,
          "destructive": false,
          "idempotent": true,
          "scopes": [
            "context:private"
          ],
          "inputParams": [
            "request_id"
          ],
          "inputSchema": {
            "properties": {
              "request_id": {
                "type": "string",
                "minLength": 1
              },
              "caller": {
                "type": "object",
                "description": "Required self-reported provenance for this call. It identifies the agent host and model for activity/audit display only; it never grants permission. Use the exact model id when exposed by the host, otherwise the literal `unknown`.",
                "properties": {
                  "agent": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Calling agent or host product, for example ChatGPT, Codex, Claude Code, or Cursor."
                  },
                  "model": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Exact model identifier when known; use `unknown` when the host does not expose it. Never guess."
                  }
                },
                "required": [
                  "agent",
                  "model"
                ],
                "additionalProperties": false
              }
            },
            "required": [
              "request_id",
              "caller"
            ],
            "type": "object",
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "description": "v3 result. Success carries the named collections below plus `space`; a business failure carries `{ok:false, error:{code, message, retryable, next_action?}}` (spec §4). `content` remains available to text-oriented clients.",
            "additionalProperties": true
          }
        }
      ]
    }
  ],
  "counts": {
    "total": 52,
    "shared": 27,
    "paired": 25
  }
}
