{"endpoint":"https://oona.ai/mcp","tools":[{"name":"absence_save","title":"Create / update / delete an absence","description":"Files (or updates, or deletes) an absence row for a user\n— vacation, unpaid_leave, or sickness. Pass `id` to update;\nadd `delete: true` to remove instead. Same role-scoped rules\nas the web UI:\n\n  - admin / employer: any user, any date.\n  - member: only their own rows; sick limited to a\n    1-day retro cap.\n\n`unpaid_leave` (ENG-1392) uses the same lifecycle as vacation\n(planned; no retroactive cap) but records the day as off-book\nfor payroll — distinct from paid vacation.\n\nBank holidays live in the web UI; no MCP tool for them\nin this iteration.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string","description":"Account prefix ID (acct_…)."},"id":{"type":"string","description":"Absence prefix ID (abs_…). Omit to create."},"user_id":{"type":"string","description":"User prefix (user_…) or @handle. Defaults to the caller for plain members; required to specify a different user for admin / employer."},"type":{"type":"string","enum":["vacation","sick","unpaid_leave"],"description":"Required on create. `unpaid_leave` shares vacation's lifecycle (no retroactive cap)."},"start_date":{"type":"string","description":"ISO date YYYY-MM-DD. Required on create."},"end_date":{"type":"string","description":"ISO date YYYY-MM-DD. Defaults to `start_date` if omitted on create."},"half_day":{"type":"boolean"},"note":{"type":["string","null"]},"delete":{"type":"boolean","description":"When true and `id` is present, delete the row. Mutually exclusive with field updates."}},"required":["account_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"absence":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string"},"user":{"type":"object"},"start_date":{"type":"string"},"end_date":{"type":"string"},"half_day":{"type":"boolean"},"note":{"type":["string","null"]}}},"deleted":{"type":"boolean","description":"True when the row was deleted."}},"type":"object"},"annotations":{"destructiveHint":true,"idempotentHint":false,"openWorldHint":false,"readOnlyHint":false},"access_tier":"gated","feature_keys":["timeclock"]},{"name":"account_list","title":"List Accounts","description":"Lists the accounts the authenticated user is a member of, plus\nthe caller's identity. Call this first — every other tool\nrequires an `account_id` argument, and the returned `roles`\ndetermine what data you see elsewhere (`[]` = regular member,\n`[\"employer\"]` and `[\"admin\"]` unlock workspace-wide reads). Use\nthe `acct_` account prefix IDs returned here on every other\ntool.\n\nNo parameters. Safe to call on every session start; never\nmutates state.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{},"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"current_user":{"type":"object","properties":{"id":{"type":"string","description":"User prefix ID (user_…)."},"handle":{"type":"string"},"name":{"type":"string"}},"required":["id","handle","name"]},"accounts":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Account prefix ID (acct_…) — pass to every other tool as account_id."},"name":{"type":"string"},"personal":{"type":"boolean","description":"True for the auto-created personal account."},"roles":{"type":"array","items":{"type":"string","enum":["admin","employer"]},"description":"Empty array = regular member."}},"required":["id","name","personal","roles"]}}},"required":["current_user","accounts"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":true},"access_tier":"basic","feature_keys":["none"]},{"name":"account_list_users","title":"List Users","description":"Lists the people on the account — resolve `@handle` mentions,\npick a `user_id` target, or show a roster.\n\nAdmin and employer callers additionally see email, phone_number,\ntime_zone (contact-sensitive data) and employment-time\nmetadata: `working_hours` — the merged shape from ENG-1434\nwith `start_at` (HH:MM), `paused_minutes`, and\n`hours_by_weekday` ({\"mon\": 8.0, …}, missing key = not a\nworkday); plus `checkin_not_required` (exempt from\nclock-in/out logic, e.g. C-level), and\n`standup_not_required`. `include_inactive` defaults to true\nso historical mentions still resolve; pass false for a live\nroster. `search` is a case-insensitive substring over handle /\nfirst_name / last_name (+ email for admin/employer).","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string","description":"Account prefix ID (e.g., acct_abc123). Discover via account_list."},"include_inactive":{"type":"boolean","description":"Include inactive (departed) users so historical @handles still resolve. Default true. Pass false for a live-roster view."},"search":{"type":"string","description":"Case-insensitive substring, 1+ chars. Matches handle / first_name / last_name (admin/employer: also email). Use for narrowing before pulling the full list."}},"required":["account_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"users":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"User prefix ID (user_…) — pass to tools that accept user_id (handle also accepted)."},"db_id":{"type":"integer","description":"Integer PK — matches user.db_id in chat/time-clock/standup response rows."},"handle":{"type":"string","description":"Unique within the account; what @handle mentions reference."},"name":{"type":"string"},"position":{"type":["string","null"],"description":"Omitted for external (guest) callers."},"remote_worker":{"type":"boolean","description":"Omitted for external (guest) callers."},"status":{"type":"string","enum":["active","inactive"],"description":"Omitted for external (guest) callers."},"roles":{"type":"array","items":{"type":"string","enum":["admin","employer"]},"description":"Empty = regular member."},"is_agent":{"type":"boolean","description":"True if this user is a bot account (AI participant). Treat the row as an agent rather than a person — don't ask the bot for human feedback; don't assign tasks expecting human work."},"email":{"type":"string","description":"Only present for admin/employer callers."},"phone_number":{"type":["string","null"],"description":"Only present for admin/employer callers."},"time_zone":{"type":["string","null"],"description":"Rails TimeZone display label (e.g. 'Berlin'), not an IANA id. Only for admin/employer callers."},"working_hours":{"type":"object","description":"ENG-1434. Merged working-hours record for this member. `start_at` HH:MM daily start, `paused_minutes` daily break, `hours_by_weekday` a map of weekday → Float hours (missing key = not a workday for this member; don't flag them missing). Only present for admin/employer callers.","properties":{"start_at":{"type":"string"},"paused_minutes":{"type":"integer"},"hours_by_weekday":{"type":"object","description":"e.g. {\"mon\": 8.0, \"fri\": 4.0}"}}},"checkin_not_required":{"type":"boolean","description":"True when the user is exempt from clock-in/out (C-level, etc.) — attendance logic must NOT flag them as missing. Only present for admin/employer callers."},"standup_not_required":{"type":"boolean","description":"True when the user is exempt from the daily standup roster. Only present for admin/employer callers."}},"required":["id","db_id","handle","name","roles","is_agent"]}}},"required":["users"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":true},"access_tier":"basic","feature_keys":["none"]},{"name":"agent_get","title":"Get Agent","description":"Returns a single agent by prefix id. The response is the\nsame payload `agent_save` and `agent_list` return —\nincluding `system_prompt`, `model`, and `tools`.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"id":{"type":"string","description":"Agent prefix id (agnt_…)."}},"required":["account_id","id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"agent":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"system_prompt":{"type":["string","null"]},"model":{"type":["string","null"]},"tools":{"type":"array","items":{"type":["string","object"]}},"active":{"type":"boolean"},"creator_role":{"type":"string"},"creator":{"type":["object","null"]},"account_id":{"type":["string","null"]},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","name","active","creator_role","created_at"]}},"required":["agent"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":true},"access_tier":"gated","feature_keys":["none"]},{"name":"agent_list","title":"List Agents","description":"Lists the account's AI agents (every agent is scoped to one\naccount and visible to all its members).\nSorted alphabetically by name.\n\nFilters (all optional):\n- `active` — true to hide retired rows, false to show only retired\n- `query` — case-insensitive substring match on name\n- `limit` — default 50, max 250","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"active":{"type":"boolean"},"query":{"type":"string"},"limit":{"type":"integer","default":50}},"required":["account_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"agents":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"system_prompt":{"type":["string","null"]},"model":{"type":["string","null"]},"tools":{"type":"array","items":{"type":["string","object"]}},"active":{"type":"boolean"},"creator_role":{"type":"string"},"creator":{"type":["object","null"]},"account_id":{"type":["string","null"]},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","name","active","creator_role","created_at"]}}},"required":["agents"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":true},"access_tier":"gated","feature_keys":["none"]},{"name":"agent_log_list","title":"List Agent Log Entries","description":"Call this before any action you might have already taken — e.g.\nbefore commenting on a task, nudging a user, or escalating\nsomething. If a recent entry shows you already did the same\naction under the same subject, escalate or move on instead of\nrepeating.\n\nReturns *your own* log entries in this account, newest first.\nOther users' entries are invisible.\n\nFilters (all optional, AND-combined):\n- `subject` — exact match. Use the same conventions as\n  `agent_log_write` (`\"task:ENG-123\"`,\n  `\"standup:user_max:2026-05-07\"`).\n- `tags` — match if the entry has *any* of the given tags\n  (OR, not AND).\n- `since` — only entries created at or after this moment.\n  Same lenient parsing as `agent_reminder_upsert.due_at`:\n  relative offset (`+30m`, `+2h`, `+1d`), ISO 8601, date-only,\n  space-separated, or Unix epoch. Note: relative offsets here\n  are *future*-anchored — to scan the last 2h pass the absolute\n  time `(Time.now - 2h).iso8601`, or just pass the date `today`.\n  Bad input → error.\n- `limit` — default 50, max 200.\n\nExample: before nudging @max again about ENG-123, call with\n`subject: \"task:ENG-123\"`, `tags: [\"estimate-reminder\"]` — if\nanything comes back from the last 24h, don't nudge again.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"subject":{"type":"string","description":"Exact-match filter, e.g. 'task:ENG-123'."},"tags":{"type":"array","items":{"type":"string"},"description":"Match if the entry has ANY of these tags (OR)."},"since":{"type":"string","description":"Only entries created at or after this moment. Accepts ISO 8601, date-only, space-separated, Unix epoch, or relative future offset. Bad input → error."},"limit":{"type":"integer","default":50,"description":"Max rows (default 50, max 200)."}},"required":["account_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"entries":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"body":{"type":"string"},"subject":{"type":["string","null"]},"tags":{"type":"array","items":{"type":"string"}},"created_at":{"type":"string"}},"required":["id","body","tags","created_at"]}}},"required":["entries"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":true},"access_tier":"gated","feature_keys":["none"]},{"name":"agent_log_write","title":"Write Agent Log Entry","description":"Call this immediately after you complete a meaningful action that\na future session might otherwise repeat — e.g. you commented on a\ntask asking for an estimate, DM'd a user about a missed standup,\nor escalated something to a workspace lead. The next session will\nread your entries via `agent_log_list` *before* acting, and skip\nduplicates.\n\nEntries are append-only, scoped to (you, this account), and\ninvisible to other users. There is no update or delete.\n\nUse a stable, machine-friendly `subject` so write and read line\nup — e.g. `\"task:ENG-123\"`, `\"standup:user_max:2026-05-07\"`,\n`\"user:user_abc123\"`. Use `tags` for short reusable labels\nyou'll filter on later, e.g. `[\"estimate-reminder\"]`,\n`[\"standup-followup\", \"escalated\"]`. Both are optional but\nstrongly recommended — without them you can only retrieve by\nrecency.\n\nExample: after asking @max for an estimate on ENG-123, call\nwith `body: \"Asked @max for estimate\"`,\n`subject: \"task:ENG-123\"`, `tags: [\"estimate-reminder\"]`.\n\n`body` ≤ 8 KB; `subject` ≤ 200 chars.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"body":{"type":"string","description":"What you just did. ≤ 8 KB."},"subject":{"type":"string","description":"Stable identifier you'll match on later, e.g. 'task:ENG-123'. ≤ 200 chars."},"tags":{"type":"array","items":{"type":"string"},"description":"Short labels for OR-filtering, e.g. ['estimate-reminder']."}},"required":["account_id","body"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"entry":{"type":"object","properties":{"id":{"type":"string"},"body":{"type":"string"},"subject":{"type":["string","null"]},"tags":{"type":"array","items":{"type":"string"}},"created_at":{"type":"string"}},"required":["id","body","tags","created_at"]}},"required":["entry"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":false,"openWorldHint":false,"readOnlyHint":false},"access_tier":"basic","feature_keys":["none"]},{"name":"agent_reminder_list_due","title":"List Due Agent Reminders","description":"Call this at the very start of every session, before doing\nanything else. It returns the reminders you previously\nscheduled for yourself that are now due — i.e. `due_at <=\nnow`, not yet completed, and created within the last 14 days.\nReminders older than 14 days are auto-hidden so the inbox\ndoesn't grow unbounded.\n\nSorted by `due_at` ascending — oldest-due first, so the most\noverdue work surfaces immediately.\n\nWorkflow per row: read the `prompt`, do the work, then call\n`agent_reminder_upsert` with the row's `id` and\n`completed: true`. If the situation changed and you want to\ndefer instead, call `agent_reminder_upsert` with the same\n`id` and a new `due_at`.\n\nFilters (all optional):\n- `subject` — exact match (e.g. `\"task:ENG-123\"`).\n- `tags` — match if the reminder has *any* of these tags.\n- `limit` — default 50, max 200.\n\nReturns *your own* reminders only; other users' reminders\nare invisible.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"subject":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"limit":{"type":"integer","default":50,"description":"Max rows (default 50, max 200)."}},"required":["account_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"reminders":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"prompt":{"type":"string"},"subject":{"type":["string","null"]},"tags":{"type":"array","items":{"type":"string"}},"due_at":{"type":"string"},"completed_at":{"type":["string","null"]},"created_at":{"type":"string"}},"required":["id","prompt","tags","due_at","created_at"]}}},"required":["reminders"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":true},"access_tier":"gated","feature_keys":["none"]},{"name":"agent_reminder_upsert","title":"Create or Update Agent Reminder","description":"Schedules a follow-up prompt for yourself, or updates one you\nalready scheduled. Use this whenever the right next step isn't\n\"do it now\" but \"check back later\" — e.g. you DM'd a user\nabout a missed standup and want to re-check in 2 hours, or\nyou asked a teammate for an estimate and want to escalate if\nit's still missing tomorrow.\n\nTwo modes, decided by whether `id` is set:\n- Without `id` → create. `prompt` and `due_at` required.\n  Returns the new reminder's `id` (`arem_…`). Repeated calls\n  without `id` create new rows (not idempotent — use a stable\n  `subject` to dedupe yourself).\n- With `id` → update. Only the fields you pass are changed.\n  Use this to:\n  - push the reminder out: pass `id` + a new `due_at`\n  - mark it handled: pass `id` + `completed: true` (idempotent)\n  - re-open: pass `id` + `completed: false`\n  - rewrite the prompt as the situation evolves.\n\nWorkflow: at session start, call `agent_reminder_list_due`\nfirst to find what's due, do the work, then call this tool\nwith `id` + `completed: true` to clear it.\n\n`due_at` accepts several formats — pick whichever is easiest:\n- **Relative offset (most convenient for \"in X\")**: `+30m`,\n  `+2h`, `+1d`, `+1w` (units: s/m/h/d/w; minutes / hours /\n  days / weeks). No spaces.\n- **ISO 8601 datetime**: `2026-05-07T10:00:00Z` or\n  `2026-05-07T12:00:00+02:00` (timezone offset preserved).\n- **Date only**: `2026-05-07` (becomes 00:00 in your timezone).\n- **Space-separated**: `2026-05-07 10:00` or\n  `2026-05-07 10:00:00`.\n- **Unix epoch seconds**: `1746604800`.\nNegative offsets are rejected (reminders are always for the\nfuture). Bad input returns an error that lists every accepted\nformat.\n\nUse the same `subject` and `tags` conventions as the logbook\n(`\"task:ENG-123\"`, `[\"standup-followup\"]`) — they make the\ninbox filterable. Reminders auto-expire 14 days after creation\nif not completed (they stop appearing in `list_due`), so don't\nuse this for long-horizon planning.\n\nScoped to (you, this account); other users can't see or update\nyour reminders. `prompt` ≤ 8 KB; `subject` ≤ 200 chars.\n\nExample (create, relative): `prompt: \"Did @max submit\nstandup? If not, DM @lead.\"`, `due_at: \"+2h\"`,\n`subject: \"standup:user_max:2026-05-07\"`,\n`tags: [\"standup-followup\"]`.\nExample (create, ISO): same `prompt`, `due_at:\n\"2026-05-07T10:00:00Z\"`.\nExample (push out 1 day): `id: \"arem_abc123\"`, `due_at: \"+1d\"`.\nExample (complete): `id: \"arem_abc123\"`, `completed: true`.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"id":{"type":"string","description":"Reminder prefix id (arem_…). Omit to create."},"prompt":{"type":"string","description":"What you want yourself to do later. Required on create. ≤ 8 KB."},"due_at":{"type":"string","description":"When the reminder becomes due. Required on create. Accepts relative offset ('+30m', '+2h', '+1d', '+1w'), ISO 8601 ('2026-05-07T10:00:00Z'), date-only ('2026-05-07'), space-separated ('2026-05-07 10:00'), or Unix epoch seconds. See tool description for full list."},"subject":{"type":["string","null"],"description":"Optional stable identifier, e.g. 'task:ENG-123'."},"tags":{"type":"array","items":{"type":"string"},"description":"Optional short labels."},"completed":{"type":"boolean","description":"true → mark handled (idempotent); false → re-open."}},"required":["account_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"reminder":{"type":"object","properties":{"id":{"type":"string"},"prompt":{"type":"string"},"subject":{"type":["string","null"]},"tags":{"type":"array","items":{"type":"string"}},"due_at":{"type":"string"},"completed_at":{"type":["string","null"]},"created_at":{"type":"string"}},"required":["id","prompt","tags","due_at","created_at"]}},"required":["reminder"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":false,"openWorldHint":false,"readOnlyHint":false},"access_tier":"gated","feature_keys":["none"]},{"name":"agent_run_create","title":"Fire an Agent Run Manually","description":"Run a routine, or run an agent with a supplied prompt. A routine uses its own agent and prompt.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"prompt":{"type":"string","description":"Required for an ad-hoc run."},"agent_id":{"type":["string","null"],"description":"Agent prefix id (agnt_…). Required unless a schedule with a bound agent is given."},"agent_schedule_id":{"type":["string","null"],"description":"Schedule prefix id (asch_…). Omit for an ad-hoc run."}},"required":["account_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"agent_run":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string"},"agent_schedule_id":{"type":["string","null"]},"agent_trigger_id":{"type":["string","null"]},"agent_id":{"type":["string","null"]},"scheduled_for":{"type":["string","null"]},"started_at":{"type":["string","null"]},"finished_at":{"type":["string","null"]},"skip_reason":{"type":["string","null"]},"created_at":{"type":"string"},"updated_at":{"type":"string"},"url":{"type":"string"},"prompt_snapshot":{"type":"string"},"result":{"type":["string","null"]},"error":{"type":["string","null"]}},"required":["id","status","prompt_snapshot","created_at","url"]}},"required":["agent_run"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":false,"openWorldHint":false,"readOnlyHint":false},"access_tier":"gated","feature_keys":["none"]},{"name":"agent_run_get","title":"Get Agent Run","description":"Returns a single `AgentRun` row by prefix id, including\nthe full `prompt_snapshot`, `result`, `error`, and\n`skip_reason` (all plain text — no Tiptap conversion).\nThe base list payload from `agent_run_list` is included;\nthis endpoint just adds the verbose fields.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"id":{"type":"string","description":"Run prefix id (arun_…)."}},"required":["account_id","id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"agent_run":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string"},"agent_schedule_id":{"type":["string","null"]},"agent_trigger_id":{"type":["string","null"]},"agent_id":{"type":["string","null"]},"scheduled_for":{"type":["string","null"]},"started_at":{"type":["string","null"]},"finished_at":{"type":["string","null"]},"skip_reason":{"type":["string","null"]},"created_at":{"type":"string"},"updated_at":{"type":"string"},"url":{"type":"string"},"prompt_snapshot":{"type":"string"},"result":{"type":["string","null"]},"error":{"type":["string","null"]}},"required":["id","status","prompt_snapshot","created_at","url"]}},"required":["agent_run"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":true},"access_tier":"gated","feature_keys":["none"]},{"name":"agent_run_list","title":"List Agent Runs","description":"Lists `AgentRun` rows the caller can see, newest first.\nScoped via `AgentRunPolicy::Scope` — members see only\nruns from their own schedules; admins and employers see\nevery run in the account.\n\nFilters (all optional):\n- `agent_schedule_id` / `agent_id` —\n  narrow by the linked record (prefix IDs)\n- `status` — \"queued\" / \"running\" / \"success\" / \"failed\"\n  / \"completed_with_errors\" (ran but a tool/action errored)\n  / \"skipped\"\n- `created_at` — return only rows created at or after\n  this moment. Accepts: ISO 8601, `YYYY-MM-DD`,\n  space-separated, Unix epoch, or a relative offset\n  like `+30m` / `+2h` / `+1d` / `+1w` (which means \"in\n  the future from now\" — useful as a sentinel, less so\n  for run-listing).\n- `limit` — default 50, max 250\n\nEach row carries a `url` field pointing at the run's\npage so a UI can link straight to it.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"agent_schedule_id":{"type":"string"},"agent_id":{"type":"string"},"status":{"type":"string","enum":["queued","running","success","failed","skipped"]},"created_at":{"type":"string","description":"Lower bound. Accepts: ISO 8601 ('2026-05-07T10:00:00Z'), date-only ('2026-05-07'), space-separated ('2026-05-07 10:00'), Unix epoch seconds ('1746604800'), or relative offset ('+30m', '+2h', '+1d', '+1w')"},"limit":{"type":"integer","default":50}},"required":["account_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"agent_runs":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string"},"agent_schedule_id":{"type":["string","null"]},"agent_trigger_id":{"type":["string","null"]},"agent_id":{"type":["string","null"]},"scheduled_for":{"type":["string","null"]},"started_at":{"type":["string","null"]},"finished_at":{"type":["string","null"]},"skip_reason":{"type":["string","null"]},"created_at":{"type":"string"},"updated_at":{"type":"string"},"url":{"type":"string"}},"required":["id","status","created_at","url"]}}},"required":["agent_runs"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":true},"access_tier":"gated","feature_keys":["none"]},{"name":"agent_save","title":"Create or Update Agent","description":"Linear-style upsert for AI agent personas. Pass `id` (prefix\n`agnt_…`) to update, omit to create.\n\nOn create:\n- `name` is required. The agent belongs to `account_id` and\n  is visible to every member of that account.\n- `creator_id` is set to the current user.\n- `creator_role` is snapshotted from your role at this\n  moment (\"admin\" or \"employer\"). The snapshot is frozen —\n  a later role change can't reach back and unlock (or\n  lock) this row.\n\nOn update:\n- Only fields you pass are changed.\n- `creator_role` is immutable.\n\n`tools` is a free-form JSON array — list whichever tool\nnames the runner expects (e.g. `[\"chat_send_message\",\n\"task_save\"]`).","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"id":{"type":"string","description":"Agent prefix id (agnt_…). Omit to create."},"name":{"type":"string","description":"Required on create. ≤ 120 chars."},"system_prompt":{"type":["string","null"]},"model":{"type":["string","null"],"description":"Model identifier the runner should use (e.g. 'claude-sonnet-4-6')."},"tools":{"type":"array","items":{"type":"string"},"description":"Tool names the runner should expose to this agent."},"active":{"type":"boolean","description":"false to retire without deleting (scheduler skips inactive agents)."}},"required":["account_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"agent":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"system_prompt":{"type":["string","null"]},"model":{"type":["string","null"]},"tools":{"type":"array","items":{"type":["string","object"]}},"active":{"type":"boolean"},"creator_role":{"type":"string"},"creator":{"type":["object","null"]},"account_id":{"type":["string","null"]},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","name","active","creator_role","created_at"]}},"required":["agent"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":false,"openWorldHint":false,"readOnlyHint":false},"access_tier":"gated","feature_keys":["none"]},{"name":"agent_schedule_get","title":"Get Agent Schedule","description":"Returns a single schedule plus every trigger and the most\nrecent runs (`recent_runs`, capped at 20, newest first).","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"id":{"type":"string","description":"Schedule prefix id (asch_…)."}},"required":["account_id","id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"agent_schedule":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":["string","null"]},"prompt":{"type":["string","null"]},"status":{"type":"string"},"concurrency":{"type":"string"},"catch_up":{"type":"string"},"catch_up_cap":{"type":"integer"},"agent_id":{"type":["string","null"]},"owner":{"type":["object","null"]},"account_id":{"type":["string","null"]},"created_at":{"type":"string"},"updated_at":{"type":"string"},"triggers":{"type":"array","items":{"type":"object"}},"recent_runs":{"type":"array","items":{"type":"object"}}},"required":["id","title","prompt","status","account_id","created_at"]}},"required":["agent_schedule"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":true},"access_tier":"gated","feature_keys":["none"]},{"name":"agent_schedule_list","title":"List Agent Schedules","description":"Lists schedule rows the caller can see — account-scoped\nplus your own private — with their triggers inlined so the\nUI doesn't need a second round-trip per row. Sorted by\n`created_at` ascending.\n\nFilters (all optional):\n- `status` — \"draft\" / \"active\" / \"paused\" / \"archived\"\n- `agent_id` — show only schedules bound to a given agent\n- `limit` — default 50, max 250","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"status":{"type":"string","enum":["draft","active","paused","archived"]},"agent_id":{"type":"string"},"limit":{"type":"integer","default":50}},"required":["account_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"agent_schedules":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":["string","null"]},"prompt":{"type":["string","null"]},"status":{"type":"string"},"concurrency":{"type":"string"},"catch_up":{"type":"string"},"catch_up_cap":{"type":"integer"},"agent_id":{"type":["string","null"]},"owner":{"type":["object","null"]},"account_id":{"type":["string","null"]},"created_at":{"type":"string"},"updated_at":{"type":"string"},"triggers":{"type":"array","items":{"type":"object"}}},"required":["id","title","prompt","status","account_id","created_at"]}}},"required":["agent_schedules"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":true},"access_tier":"gated","feature_keys":["none"]},{"name":"agent_schedule_save","title":"Create or Update Agent Schedule","description":"Create or update a routine with its own title and prompt. Runs use the selected agent. Activation requires an agent and an active trigger. Pass id to update.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"id":{"type":"string","description":"Routine prefix id (asch_…). Omit to create."},"title":{"type":"string"},"prompt":{"type":"string","description":"Instructions sent to the agent on each run."},"agent_id":{"type":"string","description":"Agent prefix id. Required before activation."},"status":{"type":"string","enum":["draft","active","paused","archived"]},"concurrency":{"type":"string","enum":["coalesce","always_enqueue","skip_if_active"]},"catch_up":{"type":"string","enum":["skip_missed","enqueue_capped"]},"catch_up_cap":{"type":"integer"}},"required":["account_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"agent_schedule":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":["string","null"]},"prompt":{"type":["string","null"]},"status":{"type":"string"},"concurrency":{"type":"string"},"catch_up":{"type":"string"},"catch_up_cap":{"type":"integer"},"agent_id":{"type":["string","null"]},"owner":{"type":["object","null"]},"account_id":{"type":["string","null"]},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","title","prompt","status","account_id","created_at"]}},"required":["agent_schedule"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":false,"openWorldHint":false,"readOnlyHint":false},"access_tier":"gated","feature_keys":["none"]},{"name":"agent_trigger_list","title":"List Agent Triggers","description":"Lists every trigger for one `AgentSchedule`, sorted by\n`next_run_at` ascending so the soonest-to-fire row comes\nfirst. Inactive (`active = false`) triggers are included —\nfilter client-side if you only want firing ones.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"agent_schedule_id":{"type":"string","description":"Schedule prefix id (asch_…)."}},"required":["account_id","agent_schedule_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"agent_triggers":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"agent_schedule_id":{"type":"string"},"frequency":{"type":"string"},"run_at":{"type":["string","null"]},"weekday":{"type":["integer","null"]},"day_of_month":{"type":["integer","null"]},"cron_expression":{"type":["string","null"]},"timezone":{"type":"string"},"next_run_at":{"type":["string","null"]},"last_run_at":{"type":["string","null"]},"active":{"type":"boolean"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","agent_schedule_id","frequency","timezone","active","created_at"]}}},"required":["agent_triggers"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":true},"access_tier":"gated","feature_keys":["none"]},{"name":"agent_trigger_save","title":"Create or Update Agent Trigger","description":"Linear-style upsert for cadence rows attached to an\n`AgentSchedule`. Pass `id` (prefix `atrg_…`) to update,\nomit to create. `agent_schedule_id` is required.\n\nFrequencies and their inputs:\n- `hourly` — fires at the top of every hour\n- `daily` — needs `run_at` (\"HH:MM\")\n- `weekly` — needs `run_at` + `weekday` (0=Sunday … 6=Saturday)\n- `monthly` — needs `run_at` + `day_of_month` (1–31; days\n  that don't exist in a given month fall to the last day)\n- `cron` — needs `cron_expression` (5-field standard cron,\n  parsed by Fugit; uses the trigger's timezone)\n\n`next_run_at` is recomputed on every save — you never set\nit directly. DST-aware: timezones like Europe/Berlin keep\nthe wall-clock hour stable across the March / October\nswitches.\n\nAuthorization delegates to the parent schedule: who can\nupdate the schedule can update its triggers.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"id":{"type":"string","description":"Trigger prefix id (atrg_…). Omit to create."},"agent_schedule_id":{"type":"string","description":"Required on create."},"frequency":{"type":"string","enum":["hourly","daily","weekly","monthly","cron"]},"run_at":{"type":["string","null"],"description":"Wall-clock time-of-day 'HH:MM' for daily/weekly/monthly."},"weekday":{"type":["integer","null"],"description":"0=Sunday … 6=Saturday. Weekly only."},"day_of_month":{"type":["integer","null"],"description":"1–31. Monthly only."},"cron_expression":{"type":["string","null"],"description":"5-field standard cron. Cron-frequency only."},"timezone":{"type":"string","description":"IANA timezone (e.g. 'Europe/Berlin'). Defaults to 'Europe/Berlin' on create."},"active":{"type":"boolean","description":"false to retire a cadence row without deleting (scheduler skips inactive triggers)."}},"required":["account_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"agent_trigger":{"type":"object","properties":{"id":{"type":"string"},"agent_schedule_id":{"type":"string"},"frequency":{"type":"string"},"run_at":{"type":["string","null"]},"weekday":{"type":["integer","null"]},"day_of_month":{"type":["integer","null"]},"cron_expression":{"type":["string","null"]},"timezone":{"type":"string"},"next_run_at":{"type":["string","null"]},"last_run_at":{"type":["string","null"]},"active":{"type":"boolean"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","agent_schedule_id","frequency","timezone","active","created_at"]}},"required":["agent_trigger"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":false,"openWorldHint":false,"readOnlyHint":false},"access_tier":"gated","feature_keys":["none"]},{"name":"attachment_upload","title":"Upload Files (presigned / inline / fetch)","description":"Uploads files and returns per file an `att_…` attachment_id plus\na `file_url` (short link, viewable for 15 min). Pass either form\nto `chat_send_message` / `task_save` / `task_comment_save` /\n`email_send` (`attachment_ids`) or `drive_file_upload`\n(`attachment_id`). Up to 10 files per call;\ntransports may be mixed per file.\n\n**Whenever you can run curl, use the presigned transport —\neverything else is slow and token-hungry.**\n\n1. PRESIGNED (preferred, ≤ 1 GB): pass exact `byte_size`\n   and base64 MD5 `checksum`:\n     openssl dgst -md5 -binary <file> | openssl base64\n   You get `upload_url` + `headers` + a ready `curl_command`;\n   PUT the raw bytes (2xx = done). `status` is\n   \"awaiting_upload\" until then — consumers reject the handle\n   with upload_incomplete before your PUT succeeded.\n\n2. INLINE (≤ 1 MB decoded): pass `base64_bytes`\n   (RFC 4648, no data-URI prefix). ONLY for clients that cannot\n   run shell commands, or truly tiny text files. DO NOT\n   hand-encode base64 — use a shell:\n     openssl base64 -A -in <file>    # portable\n     base64 -i <file>                # macOS\n\n3. FETCH (≤ 50 MB): pass `source_url` — the server\n   downloads the http(s) resource (25 s timeout, private hosts\n   refused). `filename`/`mime_type` optional here (derived from\n   the URL / response Content-Type).\n\nFinalize (attach/store) within 24 h — uploads never attached to\nanything are purged after that.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string","description":"Account prefix ID (acct_…)."},"files":{"type":"array","minItems":1,"maxItems":10,"description":"Up to 10 files. Each item uses EXACTLY ONE transport: byte_size+checksum (presigned, preferred) | base64_bytes (inline) | source_url (fetch).","items":{"type":"object","properties":{"filename":{"type":"string","description":"No path components. Required for presigned/inline; optional for source_url (derived from the URL path)."},"mime_type":{"type":"string","description":"Required for presigned/inline; optional for source_url (falls back to the response Content-Type)."},"byte_size":{"type":"integer","minimum":1,"maximum":1073741824,"description":"PRESIGNED: exact file size in bytes; storage rejects a PUT of any other size."},"checksum":{"type":"string","description":"PRESIGNED: base64 MD5 (24 chars ending '=='): openssl dgst -md5 -binary <file> | openssl base64"},"base64_bytes":{"type":"string","description":"INLINE: RFC 4648 base64, whitespace tolerated, no data-URI prefix. Max 1 MB decoded."},"source_url":{"type":"string","description":"FETCH: http(s) URL fetched server-side. Max 50 MB, 25 s timeout, private/internal hosts refused."}}}}},"required":["account_id","files"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"files":{"type":"array","items":{"type":"object","properties":{"attachment_id":{"type":"string","description":"Blob prefix id (att_…) — one of the two handle forms."},"filename":{"type":"string"},"transport":{"type":"string","enum":["presigned","inline","fetch"]},"status":{"type":"string","enum":["awaiting_upload","stored"],"description":"presigned entries stay awaiting_upload until your PUT succeeds."},"file_url":{"type":"string","format":"uri","description":"Short view link (/f/att_…) — the other handle form; browser-openable for 15 min."},"file_url_expires_at":{"type":"string","format":"date-time"},"mime_type":{"type":"string"},"byte_size":{"type":"integer"},"upload_url":{"type":"string","format":"uri","description":"presigned only: PUT target."},"headers":{"type":"object","additionalProperties":{"type":"string"},"description":"presigned only: send these exact headers with the PUT."},"curl_command":{"type":"string","description":"presigned only: ready-to-run PUT."},"upload_url_expires_at":{"type":"string","format":"date-time","description":"presigned only."}},"required":["attachment_id","filename","transport","status","file_url","file_url_expires_at","mime_type","byte_size"]}}},"required":["files"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":false,"openWorldHint":false,"readOnlyHint":false},"access_tier":"basic","feature_keys":["none"]},{"name":"calendar_event_copy","title":"Copy Calendar Event","description":"Copy one visible event into a writable calendar in the same account. Creates a single event, without guests or Google Meet. A stable request_id makes retries idempotent. Both calendars must be available in the current workspace.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"calendar_id":{"type":"string"},"event_id":{"type":"string"},"destination_calendar_id":{"type":"string"},"request_id":{"type":"string","minLength":8,"maxLength":100}},"required":["account_id","calendar_id","event_id","destination_calendar_id","request_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"event":{"type":"object","properties":{"id":{"type":"string"},"calendar_id":{"type":"string"},"title":{"type":"string"},"description":{"type":["string","null"]},"location":{"type":["string","null"]},"starts_at":{"type":"string"},"ends_at":{"type":"string"},"all_day":{"type":"boolean"},"start_on":{"type":["string","null"]},"end_on":{"type":["string","null"]},"time_zone":{"type":"string"},"version":{"type":"integer"},"google_meet_url":{"type":["string","null"]},"conference_status":{"type":["string","null"]},"reminders":{"type":"object","properties":{"useDefault":{"type":"boolean"},"overrides":{"type":"array","maxItems":5,"items":{"type":"object","properties":{"method":{"type":"string","enum":["popup","email"]},"minutes":{"type":"integer","minimum":0,"maximum":40320}},"required":["method","minutes"]}}}},"recurrence":{"type":"object","properties":{"frequency":{"type":"string","enum":["none","daily","weekly","monthly","yearly"]},"interval":{"type":"integer","minimum":1,"maximum":99},"weekdays":{"type":"array","maxItems":7,"items":{"type":"integer","minimum":1,"maximum":7}},"monthly_mode":{"type":"string","enum":["date","weekday","last_weekday","last_day"]},"ends_on":{"type":"string"},"count":{"type":"integer","minimum":1,"maximum":1000}}},"series_id":{"type":["string","null"]},"series_version":{"type":["integer","null"]},"google_recurrence":{"type":"array","items":{"type":"string"},"description":"Original Google RRULE/EXDATE/RDATE entries; preserved when recurrence is omitted on updates. Read the event directly for a fresh series version."},"invitation":{"type":"boolean"},"response_status":{"type":["string","null"]},"organizer":{"type":["string","null"]},"guests":{"type":"array","items":{"type":"object","properties":{"email":{"type":"string"},"displayName":{"type":"string"},"responseStatus":{"type":"string"},"optional":{"type":"boolean"},"organizer":{"type":"boolean"},"self":{"type":"boolean"}}}},"can_manage_guests":{"type":"boolean"},"can_edit_reminders":{"type":"boolean"},"can_respond":{"type":"boolean"},"recurring_occurrence":{"type":"boolean"},"writable":{"type":"boolean"}},"required":["id","calendar_id","title","starts_at","ends_at","all_day","time_zone","version","invitation","can_respond","recurring_occurrence","writable"]}},"required":["event"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":true,"readOnlyHint":false},"access_tier":"gated","feature_keys":["calendar"]},{"name":"calendar_event_delete","title":"Delete Calendar Event","description":"Delete one event from a calendar you can edit. Google events are deleted there too, without invitation emails. Requires the current version from a prior read. For Google series, this is the default; explicit all scope deletes the master series and requires its current series version.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"calendar_id":{"type":"string"},"event_id":{"type":"string"},"expected_version":{"type":"integer","minimum":0},"series_scope":{"type":"string","enum":["this","all","future"],"description":"Series deletion scope. Google and native calendars support this, all and future. Google future splits reset following exceptions."},"expected_series_version":{"type":"integer","minimum":0}},"required":["account_id","calendar_id","event_id","expected_version"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"deleted":{"type":"boolean"},"event_id":{"type":"string"}},"required":["deleted","event_id"],"type":"object"},"annotations":{"destructiveHint":true,"idempotentHint":true,"openWorldHint":true,"readOnlyHint":false},"access_tier":"gated","feature_keys":["calendar"]},{"name":"calendar_event_get","title":"Get Calendar Event","description":"Read one event from an explicitly permitted calendar. Returns the version required to update or delete safely.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"calendar_id":{"type":"string"},"event_id":{"type":"string","description":"Event prefix ID (evt_…)."}},"required":["account_id","calendar_id","event_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"event":{"type":"object","properties":{"id":{"type":"string"},"calendar_id":{"type":"string"},"title":{"type":"string"},"description":{"type":["string","null"]},"location":{"type":["string","null"]},"starts_at":{"type":"string"},"ends_at":{"type":"string"},"all_day":{"type":"boolean"},"start_on":{"type":["string","null"]},"end_on":{"type":["string","null"]},"time_zone":{"type":"string"},"version":{"type":"integer"},"google_meet_url":{"type":["string","null"]},"conference_status":{"type":["string","null"]},"reminders":{"type":"object","properties":{"useDefault":{"type":"boolean"},"overrides":{"type":"array","maxItems":5,"items":{"type":"object","properties":{"method":{"type":"string","enum":["popup","email"]},"minutes":{"type":"integer","minimum":0,"maximum":40320}},"required":["method","minutes"]}}}},"recurrence":{"type":"object","properties":{"frequency":{"type":"string","enum":["none","daily","weekly","monthly","yearly"]},"interval":{"type":"integer","minimum":1,"maximum":99},"weekdays":{"type":"array","maxItems":7,"items":{"type":"integer","minimum":1,"maximum":7}},"monthly_mode":{"type":"string","enum":["date","weekday","last_weekday","last_day"]},"ends_on":{"type":"string"},"count":{"type":"integer","minimum":1,"maximum":1000}}},"series_id":{"type":["string","null"]},"series_version":{"type":["integer","null"]},"google_recurrence":{"type":"array","items":{"type":"string"},"description":"Original Google RRULE/EXDATE/RDATE entries; preserved when recurrence is omitted on updates. Read the event directly for a fresh series version."},"invitation":{"type":"boolean"},"response_status":{"type":["string","null"]},"organizer":{"type":["string","null"]},"guests":{"type":"array","items":{"type":"object","properties":{"email":{"type":"string"},"displayName":{"type":"string"},"responseStatus":{"type":"string"},"optional":{"type":"boolean"},"organizer":{"type":"boolean"},"self":{"type":"boolean"}}}},"can_manage_guests":{"type":"boolean"},"can_edit_reminders":{"type":"boolean"},"can_respond":{"type":"boolean"},"recurring_occurrence":{"type":"boolean"},"writable":{"type":"boolean"}},"required":["id","calendar_id","title","starts_at","ends_at","all_day","time_zone","version","invitation","can_respond","recurring_occurrence","writable"]}},"required":["event"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":true,"readOnlyHint":true},"access_tier":"gated","feature_keys":["calendar"]},{"name":"calendar_event_invite","title":"Manage Calendar Guests and Send Invitations","description":"Replace guests of an oona or Google event you organize and send invitation updates. This sends external email. Create an event with calendar_event_save first, then read its current version. Pass every desired guest email; [] removes guests and sends cancellations. Existing guests' RSVP is preserved. Use all for a complete series with its current series version. Workspace calendar write access and this separate tool grant are required.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"calendar_id":{"type":"string"},"event_id":{"type":"string"},"expected_version":{"type":"integer","minimum":0},"guests":{"type":"array","maxItems":200,"items":{"type":"string","maxLength":254}},"series_scope":{"type":"string","enum":["this","all","future"]},"expected_series_version":{"type":"integer","minimum":0}},"required":["account_id","calendar_id","event_id","expected_version","guests"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"event":{"type":"object","properties":{"id":{"type":"string"},"calendar_id":{"type":"string"},"title":{"type":"string"},"description":{"type":["string","null"]},"location":{"type":["string","null"]},"starts_at":{"type":"string"},"ends_at":{"type":"string"},"all_day":{"type":"boolean"},"start_on":{"type":["string","null"]},"end_on":{"type":["string","null"]},"time_zone":{"type":"string"},"version":{"type":"integer"},"google_meet_url":{"type":["string","null"]},"conference_status":{"type":["string","null"]},"reminders":{"type":"object","properties":{"useDefault":{"type":"boolean"},"overrides":{"type":"array","maxItems":5,"items":{"type":"object","properties":{"method":{"type":"string","enum":["popup","email"]},"minutes":{"type":"integer","minimum":0,"maximum":40320}},"required":["method","minutes"]}}}},"recurrence":{"type":"object","properties":{"frequency":{"type":"string","enum":["none","daily","weekly","monthly","yearly"]},"interval":{"type":"integer","minimum":1,"maximum":99},"weekdays":{"type":"array","maxItems":7,"items":{"type":"integer","minimum":1,"maximum":7}},"monthly_mode":{"type":"string","enum":["date","weekday","last_weekday","last_day"]},"ends_on":{"type":"string"},"count":{"type":"integer","minimum":1,"maximum":1000}}},"series_id":{"type":["string","null"]},"series_version":{"type":["integer","null"]},"google_recurrence":{"type":"array","items":{"type":"string"},"description":"Original Google RRULE/EXDATE/RDATE entries; preserved when recurrence is omitted on updates. Read the event directly for a fresh series version."},"invitation":{"type":"boolean"},"response_status":{"type":["string","null"]},"organizer":{"type":["string","null"]},"guests":{"type":"array","items":{"type":"object","properties":{"email":{"type":"string"},"displayName":{"type":"string"},"responseStatus":{"type":"string"},"optional":{"type":"boolean"},"organizer":{"type":"boolean"},"self":{"type":"boolean"}}}},"can_manage_guests":{"type":"boolean"},"can_edit_reminders":{"type":"boolean"},"can_respond":{"type":"boolean"},"recurring_occurrence":{"type":"boolean"},"writable":{"type":"boolean"}},"required":["id","calendar_id","title","starts_at","ends_at","all_day","time_zone","version","invitation","can_respond","recurring_occurrence","writable"]}},"required":["event"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":false,"openWorldHint":true,"readOnlyHint":false},"access_tier":"gated","feature_keys":["calendar"]},{"name":"calendar_event_list","title":"List Calendar Events","description":"List cached events overlapping a time range of at most 62 days. Use ISO 8601 timestamps with explicit UTC offsets. Google calendars sync in the background; last_synced_at states freshness. Use calendar_sync when the requested range is not synchronized or freshness is insufficient. All-day end_on is exclusive. Pagination uses an offset and returns has_more.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"calendar_id":{"type":"string","description":"Calendar prefix ID (cal_…)."},"from":{"type":"string"},"to":{"type":"string"},"offset":{"type":"integer","minimum":0}},"required":["account_id","calendar_id","from","to"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"events":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"calendar_id":{"type":"string"},"title":{"type":"string"},"description":{"type":["string","null"]},"location":{"type":["string","null"]},"starts_at":{"type":"string"},"ends_at":{"type":"string"},"all_day":{"type":"boolean"},"start_on":{"type":["string","null"]},"end_on":{"type":["string","null"]},"time_zone":{"type":"string"},"version":{"type":"integer"},"google_meet_url":{"type":["string","null"]},"conference_status":{"type":["string","null"]},"reminders":{"type":"object","properties":{"useDefault":{"type":"boolean"},"overrides":{"type":"array","maxItems":5,"items":{"type":"object","properties":{"method":{"type":"string","enum":["popup","email"]},"minutes":{"type":"integer","minimum":0,"maximum":40320}},"required":["method","minutes"]}}}},"recurrence":{"type":"object","properties":{"frequency":{"type":"string","enum":["none","daily","weekly","monthly","yearly"]},"interval":{"type":"integer","minimum":1,"maximum":99},"weekdays":{"type":"array","maxItems":7,"items":{"type":"integer","minimum":1,"maximum":7}},"monthly_mode":{"type":"string","enum":["date","weekday","last_weekday","last_day"]},"ends_on":{"type":"string"},"count":{"type":"integer","minimum":1,"maximum":1000}}},"series_id":{"type":["string","null"]},"series_version":{"type":["integer","null"]},"google_recurrence":{"type":"array","items":{"type":"string"},"description":"Original Google RRULE/EXDATE/RDATE entries; preserved when recurrence is omitted on updates. Read the event directly for a fresh series version."},"invitation":{"type":"boolean"},"response_status":{"type":["string","null"]},"organizer":{"type":["string","null"]},"guests":{"type":"array","items":{"type":"object","properties":{"email":{"type":"string"},"displayName":{"type":"string"},"responseStatus":{"type":"string"},"optional":{"type":"boolean"},"organizer":{"type":"boolean"},"self":{"type":"boolean"}}}},"can_manage_guests":{"type":"boolean"},"can_edit_reminders":{"type":"boolean"},"can_respond":{"type":"boolean"},"recurring_occurrence":{"type":"boolean"},"writable":{"type":"boolean"}},"required":["id","calendar_id","title","starts_at","ends_at","all_day","time_zone","version","invitation","can_respond","recurring_occurrence","writable"]}},"has_more":{"type":"boolean"},"next_offset":{"type":["integer","null"]},"last_synced_at":{"type":["string","null"]},"sync_error":{"type":["string","null"]},"range_synchronized":{"type":"boolean"},"sync_window_start_at":{"type":["string","null"]},"sync_window_end_at":{"type":["string","null"]}},"required":["events","has_more","range_synchronized"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":true},"access_tier":"gated","feature_keys":["calendar"]},{"name":"calendar_event_move","title":"Move Calendar Event","description":"Move an event between writable calendars in the current account/workspace. Native calendars support individual recurring occurrences; Google supports standalone organizer events between calendars on the same connected Google account. Google may notify guests of the organizer change. Requires the current event version.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"calendar_id":{"type":"string"},"event_id":{"type":"string"},"destination_calendar_id":{"type":"string"},"expected_version":{"type":"integer","minimum":0}},"required":["account_id","calendar_id","event_id","destination_calendar_id","expected_version"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"event":{"type":"object","properties":{"id":{"type":"string"},"calendar_id":{"type":"string"},"title":{"type":"string"},"description":{"type":["string","null"]},"location":{"type":["string","null"]},"starts_at":{"type":"string"},"ends_at":{"type":"string"},"all_day":{"type":"boolean"},"start_on":{"type":["string","null"]},"end_on":{"type":["string","null"]},"time_zone":{"type":"string"},"version":{"type":"integer"},"google_meet_url":{"type":["string","null"]},"conference_status":{"type":["string","null"]},"reminders":{"type":"object","properties":{"useDefault":{"type":"boolean"},"overrides":{"type":"array","maxItems":5,"items":{"type":"object","properties":{"method":{"type":"string","enum":["popup","email"]},"minutes":{"type":"integer","minimum":0,"maximum":40320}},"required":["method","minutes"]}}}},"recurrence":{"type":"object","properties":{"frequency":{"type":"string","enum":["none","daily","weekly","monthly","yearly"]},"interval":{"type":"integer","minimum":1,"maximum":99},"weekdays":{"type":"array","maxItems":7,"items":{"type":"integer","minimum":1,"maximum":7}},"monthly_mode":{"type":"string","enum":["date","weekday","last_weekday","last_day"]},"ends_on":{"type":"string"},"count":{"type":"integer","minimum":1,"maximum":1000}}},"series_id":{"type":["string","null"]},"series_version":{"type":["integer","null"]},"google_recurrence":{"type":"array","items":{"type":"string"},"description":"Original Google RRULE/EXDATE/RDATE entries; preserved when recurrence is omitted on updates. Read the event directly for a fresh series version."},"invitation":{"type":"boolean"},"response_status":{"type":["string","null"]},"organizer":{"type":["string","null"]},"guests":{"type":"array","items":{"type":"object","properties":{"email":{"type":"string"},"displayName":{"type":"string"},"responseStatus":{"type":"string"},"optional":{"type":"boolean"},"organizer":{"type":"boolean"},"self":{"type":"boolean"}}}},"can_manage_guests":{"type":"boolean"},"can_edit_reminders":{"type":"boolean"},"can_respond":{"type":"boolean"},"recurring_occurrence":{"type":"boolean"},"writable":{"type":"boolean"}},"required":["id","calendar_id","title","starts_at","ends_at","all_day","time_zone","version","invitation","can_respond","recurring_occurrence","writable"]}},"required":["event"],"type":"object"},"annotations":{"destructiveHint":true,"idempotentHint":false,"openWorldHint":true,"readOnlyHint":false},"access_tier":"gated","feature_keys":["calendar"]},{"name":"calendar_event_reminders_set","title":"Set Calendar Event Alerts","description":"Change only the personal alerts on this calendar's event copy, including an external Google invitation whose title and times cannot be edited. Requires calendar write access and the current event version. Changes this occurrence only; organizer fields and other guests' alerts stay unchanged. Up to five popup alerts, or Google email alerts; useDefault true uses Google calendar defaults, false with overrides [] removes alerts.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"calendar_id":{"type":"string"},"event_id":{"type":"string"},"expected_version":{"type":"integer","minimum":0},"reminders":{"type":"object","properties":{"useDefault":{"type":"boolean"},"overrides":{"type":"array","maxItems":5,"items":{"type":"object","properties":{"method":{"type":"string","enum":["popup","email"]},"minutes":{"type":"integer","minimum":0,"maximum":40320}},"required":["method","minutes"]}}}}},"required":["account_id","calendar_id","event_id","expected_version","reminders"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"event":{"type":"object","properties":{"id":{"type":"string"},"calendar_id":{"type":"string"},"title":{"type":"string"},"description":{"type":["string","null"]},"location":{"type":["string","null"]},"starts_at":{"type":"string"},"ends_at":{"type":"string"},"all_day":{"type":"boolean"},"start_on":{"type":["string","null"]},"end_on":{"type":["string","null"]},"time_zone":{"type":"string"},"version":{"type":"integer"},"google_meet_url":{"type":["string","null"]},"conference_status":{"type":["string","null"]},"reminders":{"type":"object","properties":{"useDefault":{"type":"boolean"},"overrides":{"type":"array","maxItems":5,"items":{"type":"object","properties":{"method":{"type":"string","enum":["popup","email"]},"minutes":{"type":"integer","minimum":0,"maximum":40320}},"required":["method","minutes"]}}}},"recurrence":{"type":"object","properties":{"frequency":{"type":"string","enum":["none","daily","weekly","monthly","yearly"]},"interval":{"type":"integer","minimum":1,"maximum":99},"weekdays":{"type":"array","maxItems":7,"items":{"type":"integer","minimum":1,"maximum":7}},"monthly_mode":{"type":"string","enum":["date","weekday","last_weekday","last_day"]},"ends_on":{"type":"string"},"count":{"type":"integer","minimum":1,"maximum":1000}}},"series_id":{"type":["string","null"]},"series_version":{"type":["integer","null"]},"google_recurrence":{"type":"array","items":{"type":"string"},"description":"Original Google RRULE/EXDATE/RDATE entries; preserved when recurrence is omitted on updates. Read the event directly for a fresh series version."},"invitation":{"type":"boolean"},"response_status":{"type":["string","null"]},"organizer":{"type":["string","null"]},"guests":{"type":"array","items":{"type":"object","properties":{"email":{"type":"string"},"displayName":{"type":"string"},"responseStatus":{"type":"string"},"optional":{"type":"boolean"},"organizer":{"type":"boolean"},"self":{"type":"boolean"}}}},"can_manage_guests":{"type":"boolean"},"can_edit_reminders":{"type":"boolean"},"can_respond":{"type":"boolean"},"recurring_occurrence":{"type":"boolean"},"writable":{"type":"boolean"}},"required":["id","calendar_id","title","starts_at","ends_at","all_day","time_zone","version","invitation","can_respond","recurring_occurrence","writable"]}},"required":["event"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":true,"readOnlyHint":false},"access_tier":"gated","feature_keys":["calendar"]},{"name":"calendar_event_respond","title":"Respond to Calendar Invitation","description":"Accept, tentatively accept, or decline an oona or Google invitation as the calendar participant. Sends the response to the organizer. Requires calendar write access and the version returned by calendar_event_get. Email-derived invitations additionally require mailbox send access; configured email confirmation returns a review link. Native recurring requests respond to the series; Google changes only this occurrence.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"calendar_id":{"type":"string"},"event_id":{"type":"string"},"response":{"type":"string","enum":["accepted","tentative","declined"]},"expected_version":{"type":"integer","minimum":0}},"required":["account_id","calendar_id","event_id","response","expected_version"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"event":{"type":"object","properties":{"id":{"type":"string"},"calendar_id":{"type":"string"},"title":{"type":"string"},"description":{"type":["string","null"]},"location":{"type":["string","null"]},"starts_at":{"type":"string"},"ends_at":{"type":"string"},"all_day":{"type":"boolean"},"start_on":{"type":["string","null"]},"end_on":{"type":["string","null"]},"time_zone":{"type":"string"},"version":{"type":"integer"},"google_meet_url":{"type":["string","null"]},"conference_status":{"type":["string","null"]},"reminders":{"type":"object","properties":{"useDefault":{"type":"boolean"},"overrides":{"type":"array","maxItems":5,"items":{"type":"object","properties":{"method":{"type":"string","enum":["popup","email"]},"minutes":{"type":"integer","minimum":0,"maximum":40320}},"required":["method","minutes"]}}}},"recurrence":{"type":"object","properties":{"frequency":{"type":"string","enum":["none","daily","weekly","monthly","yearly"]},"interval":{"type":"integer","minimum":1,"maximum":99},"weekdays":{"type":"array","maxItems":7,"items":{"type":"integer","minimum":1,"maximum":7}},"monthly_mode":{"type":"string","enum":["date","weekday","last_weekday","last_day"]},"ends_on":{"type":"string"},"count":{"type":"integer","minimum":1,"maximum":1000}}},"series_id":{"type":["string","null"]},"series_version":{"type":["integer","null"]},"google_recurrence":{"type":"array","items":{"type":"string"},"description":"Original Google RRULE/EXDATE/RDATE entries; preserved when recurrence is omitted on updates. Read the event directly for a fresh series version."},"invitation":{"type":"boolean"},"response_status":{"type":["string","null"]},"organizer":{"type":["string","null"]},"guests":{"type":"array","items":{"type":"object","properties":{"email":{"type":"string"},"displayName":{"type":"string"},"responseStatus":{"type":"string"},"optional":{"type":"boolean"},"organizer":{"type":"boolean"},"self":{"type":"boolean"}}}},"can_manage_guests":{"type":"boolean"},"can_edit_reminders":{"type":"boolean"},"can_respond":{"type":"boolean"},"recurring_occurrence":{"type":"boolean"},"writable":{"type":"boolean"}},"required":["id","calendar_id","title","starts_at","ends_at","all_day","time_zone","version","invitation","can_respond","recurring_occurrence","writable"]},"confirmation_required":{"type":"boolean"},"review_url":{"type":"string"}},"required":["event"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":true,"readOnlyHint":false},"access_tier":"gated","feature_keys":["calendar"]},{"name":"calendar_event_save","title":"Create or Update Calendar Event","description":"Create or fully update an event in a calendar you can edit. Creation requires a stable request_id (8–100 characters); reuse it when retrying to avoid duplicates. Updates require event_id and expected_version from a prior read. Supply full event fields; omitted description/location are cleared. For all-day events, use start_on/end_on dates, with end_on exclusive. Timed events require starts_at/ends_at with UTC offsets. Google writes default to this occurrence; explicit all scope updates the master series. Writes never send invitations and do not edit sharing or attendees.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"calendar_id":{"type":"string"},"event_id":{"type":"string"},"request_id":{"type":"string","minLength":8,"maxLength":100},"expected_version":{"type":"integer","minimum":0},"google_meet":{"type":"boolean","description":"Optionally create a Google Meet on a supported Google calendar. Existing meetings are preserved."},"reminders":{"type":"object","properties":{"useDefault":{"type":"boolean"},"overrides":{"type":"array","maxItems":5,"items":{"type":"object","properties":{"method":{"type":"string","enum":["popup","email"]},"minutes":{"type":"integer","minimum":0,"maximum":40320}},"required":["method","minutes"]}}},"description":"Optional personal alerts. Omit to preserve. Set useDefault false and overrides [] to remove; up to five popup alerts (also in the owner's oona Inbox) or Google email alerts. Google defaults are available on Google calendars only."},"recurrence":{"type":"object","properties":{"frequency":{"type":"string","enum":["none","daily","weekly","monthly","yearly"]},"interval":{"type":"integer","minimum":1,"maximum":99},"weekdays":{"type":"array","maxItems":7,"items":{"type":"integer","minimum":1,"maximum":7}},"monthly_mode":{"type":"string","enum":["date","weekday","last_weekday","last_day"]},"ends_on":{"type":"string"},"count":{"type":"integer","minimum":1,"maximum":1000}},"description":"oona or Google calendar repeat rule. Weekdays use ISO Monday=1 through Sunday=7. Omit on update to retain the existing rule. Use frequency none to stop repeating with all/future scope."},"series_scope":{"type":"string","enum":["this","all","future"],"description":"Edit this occurrence or all events; Google and native calendars support this and following events; Google future splits reset following exceptions. Other individually edited/cancelled dates are preserved for all."},"expected_series_version":{"type":"integer","minimum":0,"description":"Required for all/future operations, from a fresh event read."},"title":{"type":"string","maxLength":500},"description":{"type":"string","maxLength":50000},"location":{"type":"string","maxLength":1000},"time_zone":{"type":"string"},"all_day":{"type":"boolean"},"start_on":{"type":"string"},"end_on":{"type":"string"},"starts_at":{"type":"string"},"ends_at":{"type":"string"}},"required":["account_id","calendar_id","title"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"event":{"type":"object","properties":{"id":{"type":"string"},"calendar_id":{"type":"string"},"title":{"type":"string"},"description":{"type":["string","null"]},"location":{"type":["string","null"]},"starts_at":{"type":"string"},"ends_at":{"type":"string"},"all_day":{"type":"boolean"},"start_on":{"type":["string","null"]},"end_on":{"type":["string","null"]},"time_zone":{"type":"string"},"version":{"type":"integer"},"google_meet_url":{"type":["string","null"]},"conference_status":{"type":["string","null"]},"reminders":{"type":"object","properties":{"useDefault":{"type":"boolean"},"overrides":{"type":"array","maxItems":5,"items":{"type":"object","properties":{"method":{"type":"string","enum":["popup","email"]},"minutes":{"type":"integer","minimum":0,"maximum":40320}},"required":["method","minutes"]}}}},"recurrence":{"type":"object","properties":{"frequency":{"type":"string","enum":["none","daily","weekly","monthly","yearly"]},"interval":{"type":"integer","minimum":1,"maximum":99},"weekdays":{"type":"array","maxItems":7,"items":{"type":"integer","minimum":1,"maximum":7}},"monthly_mode":{"type":"string","enum":["date","weekday","last_weekday","last_day"]},"ends_on":{"type":"string"},"count":{"type":"integer","minimum":1,"maximum":1000}}},"series_id":{"type":["string","null"]},"series_version":{"type":["integer","null"]},"google_recurrence":{"type":"array","items":{"type":"string"},"description":"Original Google RRULE/EXDATE/RDATE entries; preserved when recurrence is omitted on updates. Read the event directly for a fresh series version."},"invitation":{"type":"boolean"},"response_status":{"type":["string","null"]},"organizer":{"type":["string","null"]},"guests":{"type":"array","items":{"type":"object","properties":{"email":{"type":"string"},"displayName":{"type":"string"},"responseStatus":{"type":"string"},"optional":{"type":"boolean"},"organizer":{"type":"boolean"},"self":{"type":"boolean"}}}},"can_manage_guests":{"type":"boolean"},"can_edit_reminders":{"type":"boolean"},"can_respond":{"type":"boolean"},"recurring_occurrence":{"type":"boolean"},"writable":{"type":"boolean"}},"required":["id","calendar_id","title","starts_at","ends_at","all_day","time_zone","version","invitation","can_respond","recurring_occurrence","writable"]}},"required":["event"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":true,"readOnlyHint":false},"access_tier":"gated","feature_keys":["calendar"]},{"name":"calendar_list","title":"List Calendars","description":"List your own and workspace-shared calendars in one account. Agent calls only see calendars shared with their authenticated workspace. Use cal_ IDs with event tools.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string","description":"Account prefix ID (acct_…)."}},"required":["account_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"calendars":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"provider":{"type":"string","enum":["local","google"]},"time_zone":{"type":"string"},"writable":{"type":"boolean"},"last_synced_at":{"type":["string","null"]},"sync_error":{"type":["string","null"]}},"required":["id","name","provider","time_zone","writable"]}}},"required":["calendars"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":true},"access_tier":"gated","feature_keys":["calendar"]},{"name":"calendar_project_tasks_list","title":"Read Project Workload on a Workspace Calendar","description":"Read live tasks from projects displayed on a shared workspace calendar. Both calendar and project/task access are required. Workspace agents are restricted to their authenticated workspace. from/to are YYYY-MM-DD, to is exclusive, maximum 62 days. Task due_on is inclusive. A single date is a marker; undated_count counts tasks with neither date. Peak counts simultaneous open tasks, never working hours. Completed tasks are excluded by default; canceled/archived work is always excluded. Up to 1000 matching tasks contribute to workload; truncated explicitly marks incomplete totals. Page through these tasks with offset (200/page), or narrow dates/assignee if truncated. Use existing task tools to change the originals.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"workspace_id":{"type":"string"},"calendar_id":{"type":"string"},"from":{"type":"string"},"to":{"type":"string"},"assignee_id":{"type":"string","description":"user_ prefix or unassigned; omit for everyone."},"include_completed":{"type":"boolean"},"offset":{"type":"integer","minimum":0}},"required":["account_id","workspace_id","calendar_id","from","to"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"projects":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name"]}},"tasks":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"key":{"type":"string"},"title":{"type":"string"},"project_id":{"type":"string"},"assignee_id":{"type":["string","null"]},"start_on":{"type":["string","null"]},"due_on":{"type":["string","null"]},"status":{"type":["string","null"]}},"required":["id","key","title","project_id","assignee_id","start_on","due_on","status"]}},"people":{"type":"array","items":{"type":"object","properties":{"user_id":{"type":["string","null"]},"name":{"type":"string"},"task_count":{"type":"integer"},"peak_open_tasks":{"type":"integer"}},"required":["user_id","name","task_count","peak_open_tasks"]}},"undated_count":{"type":"integer"},"truncated":{"type":"boolean"},"has_more":{"type":"boolean"},"next_offset":{"type":["integer","null"]}},"required":["projects","tasks","people","undated_count","truncated","has_more","next_offset"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":true},"access_tier":"gated","feature_keys":["calendar"]},{"name":"calendar_projects_set","title":"Choose Projects for a Workspace Calendar","description":"Replace the projects displayed on an existing shared workspace calendar. Human calendar owners and workspace managers only. Project IDs must belong to this workspace. An empty list removes all project overlays. This changes the workspace's shared display setting; it does not create calendar events, grant project access or write to Google.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"workspace_id":{"type":"string"},"calendar_id":{"type":"string"},"project_ids":{"type":"array","items":{"type":"string"}}},"required":["account_id","workspace_id","calendar_id","project_ids"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"calendar_id":{"type":"string"},"workspace_id":{"type":"string"},"project_ids":{"type":"array","items":{"type":"string"}}},"required":["calendar_id","workspace_id","project_ids"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":false},"access_tier":"gated","feature_keys":["calendar"]},{"name":"calendar_request_list","title":"List Calendar Invitations","description":"List incoming oona and email calendar invitations, including response status, version and linked event. Agent calls see only requests from mailboxes or calendars shared with their authenticated workspace. No import or response is performed.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"pending_only":{"type":"boolean"},"limit":{"type":"integer","minimum":1,"maximum":100}},"required":["account_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"requests":{"type":"array","items":{"type":"object"}}},"required":["requests"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":true},"access_tier":"gated","feature_keys":["calendar"]},{"name":"calendar_request_respond","title":"Respond to an Incoming Calendar Request","description":"Accept, tentatively accept or decline an incoming oona/email invitation. This sends a response. For Yes/Maybe choose a writable oona calendar owned by the invited person; an existing linked Google event is reused. Email requests require mailbox sending access and both features. Agents need the mailbox and destination calendar shared with the same authenticated workspace. If email-send confirmation is configured, returns a review URL without changing or sending anything.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"request_id":{"type":"string"},"calendar_id":{"type":"string"},"response":{"type":"string","enum":["accepted","tentative","declined"]},"expected_version":{"type":"integer","minimum":0}},"required":["account_id","request_id","response","expected_version"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"request":{"type":"object"},"confirmation_required":{"type":"boolean"},"review_url":{"type":"string"}},"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":true,"readOnlyHint":false},"access_tier":"gated","feature_keys":["calendar"]},{"name":"calendar_share","title":"Share an Owned Calendar with a Workspace","description":"Set or revoke workspace access to a calendar you own. Human owners only: agents cannot grant themselves resource access. Permission none revokes this workspace, read permits viewing, write permits editing. Other workspace grants are unchanged. Shared calendars appear under the workspace, never in another member's personal Calendar.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"calendar_id":{"type":"string"},"workspace_id":{"type":"string"},"permission":{"type":"string","enum":["none","read","write"]}},"required":["account_id","calendar_id","workspace_id","permission"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"calendar_id":{"type":"string"},"workspace_id":{"type":"string"},"permission":{"type":"string"}},"required":["calendar_id","workspace_id","permission"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":false},"access_tier":"gated","feature_keys":["calendar"]},{"name":"calendar_sync","title":"Sync Google Calendar","description":"Request a Google calendar refresh for an explicit range of at most 62 days, using ISO 8601 timestamps with UTC offsets. Requires access to that calendar. Returns immediately; use calendar_event_list afterward to check last_synced_at and range_synchronized. Local calendars need no synchronization.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"calendar_id":{"type":"string"},"from":{"type":"string"},"to":{"type":"string"}},"required":["account_id","calendar_id","from","to"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"queued":{"type":"boolean"},"calendar_id":{"type":"string"},"last_synced_at":{"type":["string","null"]}},"required":["queued","calendar_id"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":true,"readOnlyHint":false},"access_tier":"gated","feature_keys":["calendar"]},{"name":"chat_add_reaction","title":"Add Chat Reaction","description":"Adds an emoji reaction to a chat message. Idempotent —\nretrying the same `(message, user, emoji)` triple returns\n`already_existed: true` instead of erroring. A single user\nmay stack multiple different emojis on the same message.\n\nResponse carries the full current reaction list, so you don't\nneed a follow-up `chat_get_messages`. Channel membership is\nrequired; admin/employer do NOT override (same rule as\n`chat_send_message`).","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string","description":"Account prefix ID (e.g., acct_abc123)."},"channel_id":{"type":"string","description":"Channel prefix ID (e.g., chan_xyz789) — must be a channel you can post in."},"message_id":{"type":"string","description":"Message prefix ID (e.g., msg_abc123) of the target. Both roots and replies accept reactions."},"emoji":{"type":"string","minLength":1,"maxLength":32,"description":"Unicode emoji (e.g., 🔥, 👍, ✅). Do not escape the string — send literal Unicode, not \\u1f525 sequences. Up to 32 chars so modifier sequences (skin tone, ZWJ) still fit."}},"required":["account_id","channel_id","message_id","emoji"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"message_id":{"type":"string"},"emoji":{"type":"string"},"already_existed":{"type":"boolean","description":"True when the reaction already existed before this call — idempotent retry confirmation."},"reactions":{"type":"array","description":"Complete current reaction list for the message after this call, ordered by created_at ASC.","items":{"type":"object","properties":{"emoji":{"type":"string"},"user":{"type":"object","properties":{"id":{"type":"string"},"handle":{"type":"string"},"name":{"type":"string"}}},"created_at":{"type":"string","format":"date-time"}},"required":["emoji","user","created_at"]}}},"required":["message_id","emoji","already_existed","reactions"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":false},"access_tier":"basic","feature_keys":["chat"]},{"name":"chat_channel_save","title":"Create, Update or Archive Chat Channel","description":"Admins and employers manage public/private channels they can access.\nOmit id to create; name and workspace_id are required and channel_type\ndefaults to public. The creator joins as a channel admin. Pass a chan_…\nid to change only supplied fields. Set archived: true to archive or\nfalse to restore, preserving messages and memberships.\nEmployers need workspace access; private channels also require channel\nmembership or workspace-manager access. Changing public/private on an\nexisting channel requires an account admin or workspace manager.\nmember_ids replaces a private channel's roster, retaining the creator\nand acting user if already members. Members must be active and have\nworkspace access. Omit member_ids to preserve the roster; [] removes\nother members. Restore an archived channel before changing its roster.\nPublic-channel agents are assigned through workspace settings.\nAgents in private rosters must already be deployed to the workspace.\nChannels cannot move workspace here. Restore an archived workspace\nbefore managing its channels. DMs use chat_start_dm.\nDiscover IDs and archived channels with chat_list_channels.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string","description":"Account prefix ID (acct_…)."},"id":{"type":"string","description":"Channel prefix ID (chan_…). Omit to create."},"workspace_id":{"type":"string","description":"Required on create: workspace prefix ID (wsp_…) or key. Immutable on update."},"name":{"type":"string","description":"Required on create; at most 100 characters."},"description":{"type":["string","null"],"description":"Plain text. Null or an empty string clears it."},"channel_type":{"type":"string","enum":["public","private"]},"archived":{"type":"boolean","description":"Existing channel only: true archives, false restores."},"member_ids":{"type":"array","items":{"type":"string"},"description":"Private channels only: complete desired roster of user_… IDs or @handles. Creator and existing acting member are retained."}},"required":["account_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"channel":{"type":"object","properties":{"id":{"type":"string","description":"Channel prefix ID (chan_…) — pass to chat_get_messages / chat_send_message."},"workspace_id":{"type":["string","null"],"description":"Null for account-wide DMs."},"name":{"type":"string"},"channel_type":{"type":"string","enum":["public","private","direct"]},"description":{"type":["string","null"]},"is_archived":{"type":"boolean"},"last_message_at":{"type":["string","null"],"description":"ISO 8601 timestamp; null if no messages yet."},"is_member":{"type":"boolean","description":"Whether the caller is a member of this channel."},"member_ids":{"type":"array","items":{"type":"string"},"description":"Current roster as user_… prefix IDs."}},"required":["id","workspace_id","name","channel_type","is_archived","is_member"]}},"required":["channel"],"type":"object"},"annotations":{"destructiveHint":true,"idempotentHint":false,"openWorldHint":false,"readOnlyHint":false},"access_tier":"gated","feature_keys":["chat"]},{"name":"chat_get_messages","title":"Get Chat Messages","description":"Reads messages from a chat channel or DM. Two response shapes:\n\n- Default (\"channel view\"): root threads with their replies\n  nested underneath each root. Sorted oldest-first within the\n  returned window — `messages[last]` is the newest.\n- Thread view (`parent_message_id` set): flat list of replies,\n  no nesting (oona supports one thread level).\n\n`limit` (1-200, default 50) caps ROOT count — replies always\ncome along in full, even outside the time filter (context\npreserved). `before_id` pages backwards by root id. See Server\nInstructions for date-filter semantics.\n\nAttachments + reactions inline on every message (bulk-loaded).\n`download_url` is signed + 30-min valid.\n\nAccess: the channel must be inside one of the caller's workspaces.\nPublic channels and joined private/DM channels are readable;\naccount admins may read every channel in the tenant.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string","description":"Account prefix ID (e.g., acct_abc123)."},"channel_id":{"type":"string","description":"Channel prefix ID (e.g., chan_xyz789) from chat_list_channels."},"limit":{"type":"integer","minimum":1,"maximum":200,"description":"Max ROOT threads (replies are always fully loaded). Default 50."},"before_id":{"type":"string","description":"Paginate backwards: pass the oldest ROOT id from your previous response (msg_…) to get the next older page. Ignored in thread view."},"since":{"type":"string","format":"date-time","description":"Only return roots with created_at >= this ISO 8601 timestamp (e.g., 2026-04-21T00:00:00Z). Ignored in thread view."},"until":{"type":"string","format":"date-time","description":"Only return roots with created_at < this ISO 8601 timestamp. Ignored in thread view."},"start_date":{"type":"string","format":"date","description":"Calendar-day lower bound on root created_at (beginning of day in UTC). Use for single-day or multi-day ranges. Ignored in thread view."},"end_date":{"type":"string","format":"date","description":"Calendar-day upper bound (end of day). Defaults to start_date when only start_date is given — pair them for a range. Ignored in thread view."},"parent_message_id":{"type":"string","description":"Switch to flat thread view: return only replies to this root (msg_…). Time filters and limit are ignored."}},"required":["account_id","channel_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"channel":{"type":"object","properties":{"id":{"type":"string","description":"Channel prefix ID (chan_…)."},"name":{"type":"string"}},"required":["id","name"]},"messages":{"type":"array","description":"Channel view: roots with `replies` nested. Thread view: flat list of replies (no `replies` field).","items":{"type":"object","properties":{"id":{"type":"string","description":"Message prefix ID (msg_…)."},"body":{"type":"string"},"user":{"type":"object","properties":{"id":{"type":["string","null"]},"handle":{"type":["string","null"]},"name":{"type":"string"}}},"created_at":{"type":"string","format":"date-time"},"parent_message_id":{"type":["string","null"],"description":"null for roots; parent root's msg_… for replies."},"replies_count":{"type":"integer"},"reactions":{"type":"array","description":"Flat list of all emoji reactions on this message, ordered by created_at ASC. Group by `emoji` client-side for counts.","items":{"type":"object","properties":{"emoji":{"type":"string","description":"Unicode emoji."},"user":{"type":"object","properties":{"id":{"type":["string","null"]},"handle":{"type":["string","null"]},"name":{"type":"string"}}},"created_at":{"type":"string","format":"date-time"}},"required":["emoji","user","created_at"]}},"attachments":{"type":"array","description":"Files attached to this message, ordered by upload time. download_url is a signed URL valid for 30 minutes — possession is the capability.","items":{"type":"object","properties":{"id":{"type":"string","description":"Blob prefix ID (att_…)."},"filename":{"type":"string"},"mime_type":{"type":"string"},"byte_size":{"type":"integer"},"download_url":{"type":"string","format":"uri"},"created_at":{"type":"string","format":"date-time"}},"required":["id","filename","mime_type","byte_size","download_url","created_at"]}},"replies":{"type":"array","description":"Only present in channel view, on root messages.","items":{"type":"object"}}},"required":["id","body","user","created_at","parent_message_id","replies_count","reactions","attachments"]}}},"required":["channel","messages"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":true},"access_tier":"basic","feature_keys":["chat"]},{"name":"chat_list_channels","title":"List Chat Channels","description":"Lists chat channels the caller can see: public/private channels inside\ntheir workspaces,\npublic channels, private channels the caller joined (admins also\nsee every private one), and the caller's DMs. Archived\nchannels are hidden unless `include_archived: true`.\n\nOrdered public → private → direct, then alphabetically by name\nwithin each group. Note: DMs appear here only if a DM was\nalready started with that partner — use `chat_start_dm` to\ninitiate a new one.\nAdmins and employers can create, edit, archive and restore shared\nchannels with chat_channel_save, subject to workspace/channel access.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string","description":"Account prefix ID (e.g., acct_abc123). Discover via account_list."},"workspace_id":{"type":"string","description":"Optional workspace prefix ID (wsp_…) or key. When present, returns only public/private channels in that workspace; account-wide DMs are omitted."},"include_archived":{"type":"boolean","description":"Include archived channels (hidden from the web sidebar). Default false. Set true to search an archived channel by name."}},"required":["account_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"channels":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Channel prefix ID (chan_…) — pass to chat_get_messages / chat_send_message."},"workspace_id":{"type":["string","null"],"description":"Null for account-wide DMs."},"name":{"type":"string"},"channel_type":{"type":"string","enum":["public","private","direct"]},"description":{"type":["string","null"]},"is_archived":{"type":"boolean"},"last_message_at":{"type":["string","null"],"description":"ISO 8601 timestamp; null if no messages yet."},"is_member":{"type":"boolean","description":"Whether the caller is a member of this channel."}},"required":["id","workspace_id","name","channel_type","is_archived","is_member"]}}},"required":["channels"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":true},"access_tier":"basic","feature_keys":["chat"]},{"name":"chat_remove_reaction","title":"Remove Chat Reaction","description":"Removes the caller's own emoji reaction from a chat message.\nNo `user_id` param — moderation of others' reactions stays in\nthe web UI. Error if the caller hasn't reacted with that emoji.\nResponse echoes the remaining reactions on the message.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string","description":"Account prefix ID (e.g., acct_abc123)."},"channel_id":{"type":"string","description":"Channel prefix ID (e.g., chan_xyz789)."},"message_id":{"type":"string","description":"Message prefix ID (e.g., msg_abc123) of the target."},"emoji":{"type":"string","minLength":1,"maxLength":32,"description":"The exact emoji string you added (Unicode — same value you passed to chat_add_reaction)."}},"required":["account_id","channel_id","message_id","emoji"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"message_id":{"type":"string"},"emoji":{"type":"string"},"removed":{"type":"boolean"},"reactions":{"type":"array","description":"Reactions remaining on the message after removal, ordered by created_at ASC.","items":{"type":"object","properties":{"emoji":{"type":"string"},"user":{"type":"object","properties":{"id":{"type":"string"},"handle":{"type":"string"},"name":{"type":"string"}}},"created_at":{"type":"string","format":"date-time"}},"required":["emoji","user","created_at"]}}},"required":["message_id","emoji","removed","reactions"],"type":"object"},"annotations":{"destructiveHint":true,"idempotentHint":false,"openWorldHint":false,"readOnlyHint":false},"access_tier":"basic","feature_keys":["chat"]},{"name":"chat_send_message","title":"Send Chat Message","description":"Posts a message to a chat channel or DM — optionally with file\nattachments (images, PDFs, video, any MIME type). Synchronous:\nhits the DB and Turbo-broadcasts to members before returning.\n\n- Body is GFM Markdown, ≤ 32 KB. `@handle` mentions resolve\n  against active account members; response's `mentions` echoes\n  what mapped (resolve handles via `account_list_users`).\n- `attachment_ids` entries come from `attachment_upload` —\n  pass the `att_…` id or the `file_url`, either works. Body\n  becomes optional when at least one attachment is present.\n- `parent_message_id` threads the post (single-level only).\n- Not idempotent — retries create duplicate rows.\n- Workspace members can post to public channels and their threads\n  without joining the channel. Private channels and DMs require\n  channel membership; account admins retain tenant-wide access.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string","description":"Account prefix ID (e.g., acct_abc123)."},"channel_id":{"type":"string","description":"Channel prefix ID (e.g., chan_xyz789) from chat_list_channels."},"body":{"type":"string","maxLength":32768,"description":"Markdown content. Do not escape the string — use literal newlines and special characters, not escape sequences. Supports GFM plus @handle mentions (resolved against active account members). Max 32 KB. Optional when attachment_ids is present."},"parent_message_id":{"type":"string","description":"Thread this reply under this root message's prefix ID (msg_…). Single-level threading only — replies to replies are rejected."},"attachment_ids":{"type":"array","maxItems":20,"items":{"type":"string"},"description":"Attachment handles from attachment_upload — att_… ids or file_urls, mixed freely. Each blob may only be attached to one chat message. Body may be empty when at least one attachment is present."}},"required":["account_id","channel_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"message":{"type":"object","properties":{"id":{"type":"string","description":"Message prefix ID (msg_…)."},"body":{"type":"string"},"user":{"type":"object","properties":{"id":{"type":["string","null"]},"handle":{"type":["string","null"]},"name":{"type":"string"}}},"created_at":{"type":"string","format":"date-time"},"parent_message_id":{"type":["string","null"]},"replies_count":{"type":"integer"},"mentions":{"type":"object","description":"Server-side resolution of @handle tokens in body — confirms what you intended actually mapped.","properties":{"resolved_users":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"handle":{"type":"string"},"name":{"type":"string"}}}},"mention_all":{"type":"boolean","description":"True when `@all` was used."}}},"reactions":{"type":"array","description":"Always an empty array on a freshly-sent message — here for shape parity with chat_get_messages.","items":{"type":"object"}},"attachments":{"type":"array","description":"Files attached to this message (via attachment_ids). Same shape as chat_get_messages.","items":{"type":"object","properties":{"id":{"type":"string"},"filename":{"type":"string"},"mime_type":{"type":"string"},"byte_size":{"type":"integer"},"download_url":{"type":"string","format":"uri","description":"Signed URL, valid 30 minutes."},"created_at":{"type":"string","format":"date-time"}}}}},"required":["id","body","user","created_at","parent_message_id","replies_count","mentions","reactions","attachments"]}},"required":["message"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":false,"openWorldHint":false,"readOnlyHint":false},"access_tier":"basic","feature_keys":["chat"]},{"name":"chat_start_dm","title":"Start Direct Message","description":"Find-or-create the account-wide 1-on-1 DM channel with another\ninternal account member. A second call with the same participant\nreturns the same `chan_…` id and\nun-archives a dormant DM (matching the web UI's \"New DM\" picker).\n\nUse when `chat_list_channels` doesn't already show a DM with\nthe partner. Both participants must be active internal members of the\nsame account; guests cannot create, see, or receive DMs. DMing yourself\nis rejected.\n`name` on the returned\nchannel is an opaque internal id — render the partner's handle\nin UI copy instead.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string","description":"Account prefix ID (e.g., acct_abc123)."},"user_id":{"type":"string","description":"Partner's prefix ID (user_…), @handle, or bare handle (e.g., 'kurth' or '@kurth'). Must be an active internal member of the account."}},"required":["account_id","user_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"channel":{"type":"object","properties":{"id":{"type":"string","description":"Channel prefix ID (chan_…) — pass to chat_send_message / chat_get_messages."},"workspace_id":{"type":["string","null"],"description":"Always null for account-wide DMs."},"name":{"type":"string","description":"Opaque internal name; render the partner's handle in UI copy."},"channel_type":{"type":"string","enum":["direct"]},"description":{"type":["string","null"]},"is_archived":{"type":"boolean"},"last_message_at":{"type":["string","null"],"format":"date-time"},"is_member":{"type":"boolean"}},"required":["id","workspace_id","name","channel_type","is_archived","is_member"]}},"required":["channel"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":false},"access_tier":"basic","feature_keys":["chat"]},{"name":"cycle_get","title":"Get Cycle","description":"Fetches a single cycle by prefix id (`cyc_…`). Returns the\ncycle's window, status, bucket (current / upcoming / past\nrelative to today), the owning workspace, and progress stats —\ntotal tasks, completed count, completion ratio.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"id":{"type":"string","description":"Cycle prefix ID (cyc_…)."}},"required":["account_id","id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"cycle":{"type":"object","properties":{"id":{"type":"string"},"number":{"type":"integer"},"name":{"type":["string","null"]},"description":{"type":["string","null"]},"status":{"type":"string","enum":["planned","active","completed","cancelled"]},"starts_on":{"type":"string","format":"date"},"ends_on":{"type":"string","format":"date"},"bucket":{"type":"string","enum":["current","upcoming","past"]},"workspace":{"type":"object"},"progress":{"type":"object","properties":{"total_tasks":{"type":"integer"},"completed_tasks":{"type":"integer"},"completion_ratio":{"type":"number","description":"0.0 to 1.0; 0.0 when there are no tasks yet."}}}},"required":["id","number","status","starts_on","ends_on","bucket","workspace","progress"]}},"required":["cycle"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":true},"access_tier":"gated","feature_keys":["projects_tasks"]},{"name":"cycle_list","title":"List Cycles","description":"Lists cycles the caller can see. Cycles are per-workspace sprint\nwindows with a monotonic `number` per workspace (never reused\nacross deletions) and a `status` (planned / active / completed\n/ cancelled). At most one cycle per workspace is `active` at a time.\n\nFilter by `workspace_id`, `status`, or `bucket` (`current` /\n`upcoming` / `past`, computed from today's date). Sorted by\nstart date ascending. Archived rows are excluded.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"workspace_id":{"type":"string","description":"Workspace prefix ID or key (e.g. ENG)."},"status":{"type":"string","enum":["planned","active","completed","cancelled"]},"bucket":{"type":"string","enum":["current","upcoming","past"],"description":"Time-window relative to today."},"limit":{"type":"integer","default":50}},"required":["account_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"cycles":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Cycle prefix ID (cyc_…)."},"number":{"type":"integer","description":"Auto-increment per workspace, monotonic across deletions."},"name":{"type":["string","null"],"description":"Optional label; falls back to 'Cycle #<number>'."},"status":{"type":"string","enum":["planned","active","completed","cancelled"]},"starts_on":{"type":"string","format":"date"},"ends_on":{"type":"string","format":"date"},"workspace":{"type":"object","properties":{"id":{"type":"string"},"key":{"type":"string"},"name":{"type":"string"}}},"bucket":{"type":"string","enum":["current","upcoming","past"],"description":"Computed from today's date."}},"required":["id","number","status","starts_on","ends_on","workspace","bucket"]}}},"required":["cycles"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":true},"access_tier":"gated","feature_keys":["projects_tasks"]},{"name":"drive_activity","title":"Drive Activity Log","description":"Returns the audit log for a drive — same rows the Activity tab\nrenders. Filter by `kinds` (an array of action strings) or\n`since` (ISO 8601 / relative offset). Sorted `created_at DESC`,\ncapped at 100 rows per call. Manager only.\n\nCommon action strings: `file_uploaded`, `file_downloaded`,\n`file_renamed`, `file_moved`, `file_trashed`, `file_restored`,\n`file_purged`, `file_fetched`, `folder_created`, `folder_moved`,\n`folder_trashed`, `folder_restored`, `bulk_zip_downloaded`,\n`link_created`, `link_updated`, `link_revoked`, `link_restored`,\n`link_downloaded`, `drive_created`, `drive_archived`,\n`drive_restored`.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"drive_id":{"type":"string"},"kinds":{"type":"array","items":{"type":"string"},"description":"Filter to these action strings only."},"since":{"type":"string","description":"ISO 8601, date, or relative offset (`-1d`, `-2h`). Rows older than this are dropped."}},"required":["account_id","drive_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"drive_id":{"type":"string"},"count":{"type":"integer"},"events":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"action":{"type":"string"},"actor":{"type":["object","null"],"description":"User who did it, or null for anonymous public-link downloads."},"target_type":{"type":["string","null"]},"target_id":{"type":["string","null"],"description":"Prefix ID of the DriveFile / DriveFolder / DriveLink if applicable."},"payload":{"type":"object"},"created_at":{"type":"string","format":"date-time"}}}}},"required":["drive_id","count","events"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":true},"access_tier":"gated","feature_keys":["files"]},{"name":"drive_changes","title":"Track Drive changes","description":"Reads ordered file and folder changes in a Drive since a persistent cursor.\nIncludes create, content update, rename, move, delete and restore (create\nwith the original ID). Start with cursor 0; persist the returned cursor\nonly after processing the page. While has_more is true, request another\npage with that cursor. Cursors belong to one Drive. This is polling, not\na subscription. Use drive_activity for human activity/actors instead.\nReturns metadata only, never file contents, storage keys or signed URLs.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string","description":"Account prefix ID (acct_…)."},"drive_id":{"type":"string","description":"Drive prefix ID (drv_…)."},"cursor":{"type":"integer","minimum":0,"description":"Last successfully processed cursor for this Drive; default 0."},"limit":{"type":"integer","minimum":1,"maximum":500,"description":"Page size; default 100, maximum 500."}},"required":["account_id","drive_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"drive_id":{"type":"string"},"cursor":{"type":"integer"},"has_more":{"type":"boolean"},"changes":{"type":"array","items":{"type":"object","properties":{"sequence":{"type":"integer"},"id":{"type":"string"},"kind":{"type":"string","enum":["file","folder"]},"parent_id":{"type":["string","null"]},"name":{"type":"string"},"version":{"type":"integer"},"operation":{"type":"string","enum":["create","update","delete","move","rename"]},"deleted":{"type":"boolean"},"size":{"type":"integer"},"content_version":{"type":"string"}},"required":["sequence","id","kind","parent_id","name","version","operation","deleted"]}}},"required":["drive_id","cursor","has_more","changes"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":true},"access_tier":"gated","feature_keys":["files"]},{"name":"drive_file_content","title":"Read File (text/Markdown body)","description":"Returns the inline body of a text-family file (Markdown,\nplain text, log, csv, or any `text/*` MIME) as a UTF-8 string.\nByte cap: 256 KB — larger files are\ntruncated and `truncated: true` is set on the response.\n\nThis is the same content path the in-app Quick-Look preview\nuses, minus the redcarpet HTML render. For images, PDFs, or\nanything binary → returns `error: unsupported_kind` and a hint\nto use `drive_file_get`'s download URL.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"file_id":{"type":"string"},"max_bytes":{"type":"integer","minimum":1,"description":"Optional byte cap smaller than the default 256 KB."}},"required":["account_id","file_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"id":{"type":"string"},"name":{"type":"string"},"content_type":{"type":["string","null"]},"byte_size":{"type":"integer"},"sync_version":{"type":"integer"},"content":{"type":"string"},"truncated":{"type":"boolean"}},"required":["id","name","content_type","byte_size","sync_version","content","truncated"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":true},"access_tier":"gated","feature_keys":["files"]},{"name":"drive_file_get","title":"Get File Metadata + Download URL","description":"Returns a single file's metadata plus a short-lived signed\ndownload URL (5-minute TTL, `disposition=attachment`). The\nURL is the same one the in-app Download button would emit,\nso anything that can fetch a signed Active Storage blob works.\n\nFor inline preview of Markdown / text bodies, prefer\n`drive_file_content` — no signed-URL fetch needed.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"file_id":{"type":"string","description":"File prefix ID (dfi_…) from drive_folder_list or drive_search."}},"required":["account_id","file_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"id":{"type":"string"},"name":{"type":"string"},"content_type":{"type":["string","null"]},"byte_size":{"type":"integer"},"sync_version":{"type":"integer"},"folder_id":{"type":["string","null"]},"drive_id":{"type":"string"},"path":{"type":"string","description":"Drive name + folder chain joined by ' / '."},"uploaded_by":{"type":["object","null"]},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"download_url":{"type":"string","description":"Signed Active Storage URL, 5-minute expiry, disposition=attachment."},"has_active_share_link":{"type":"boolean"}},"required":["id","name","content_type","byte_size","sync_version","folder_id","drive_id","path","uploaded_by","created_at","updated_at","download_url","has_active_share_link"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":true},"access_tier":"gated","feature_keys":["files"]},{"name":"drive_file_save","title":"Update, Rename or Move File","description":"Renames a file (`name`) and/or moves it into another folder\nwithin the same drive (`folder_id`, null moves to root).\nTo replace content while preserving the file ID, upload the new bytes\nwith `attachment_upload`, then pass `attachment_id` and `base_version`\nfrom the last `drive_file_content` or `drive_file_get` read.\nA stale base_version returns version_conflict without changing the file;\nre-read the current file and merge your edits before retrying.\nPrevious content is retained in file history and changes sync to Macs.\n\nCross-drive moves are not supported (validation would reject\nthem). Access: `DriveFilePolicy#update?` — editor or higher.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"id":{"type":"string","description":"File prefix ID (dfi_…)."},"name":{"type":"string","maxLength":255},"folder_id":{"type":["string","null"],"description":"Destination folder (dfo_…) in the SAME drive. Pass null to move to root."},"attachment_id":{"type":"string","description":"att_… ID or file_url from attachment_upload with replacement bytes."},"base_version":{"type":"integer","minimum":0,"description":"Last-read sync_version. Required when replacing content; also accepted for rename/move."}},"required":["account_id","id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"id":{"type":"string"},"name":{"type":"string"},"folder_id":{"type":["string","null"]},"drive_id":{"type":"string"},"sync_version":{"type":"integer"}},"required":["id","name","folder_id","drive_id","sync_version"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":false,"openWorldHint":false,"readOnlyHint":false},"access_tier":"gated","feature_keys":["files"]},{"name":"drive_file_trash","title":"Move File to Trash","description":"Soft-deletes a file — moves it into the drive's Trash, where a\nManager can restore or permanently purge it. Same behaviour as\nthe in-app row Delete action. Content stays in Active Storage\nuntil purge.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"id":{"type":"string","description":"File prefix ID (dfi_…)."}},"required":["account_id","id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"id":{"type":"string"},"trashed":{"type":"boolean"}},"required":["id","trashed"],"type":"object"},"annotations":{"destructiveHint":true,"idempotentHint":false,"openWorldHint":false,"readOnlyHint":false},"access_tier":"gated","feature_keys":["files"]},{"name":"drive_file_upload","title":"Store File in a Drive","description":"Stores an uploaded file in a drive. Upload first via\n`attachment_upload`, then pass the returned handle here —\neither the `att_…` attachment_id or the `file_url`. For\npresigned uploads the PUT must have completed, otherwise this\nreturns `upload_incomplete`.\n\n`filename` is the name inside the drive (used verbatim; a\nsibling collision auto-renames to \"name (1).ext\"). MIME type\nand byte size come from the uploaded blob.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"drive_id":{"type":"string"},"folder_id":{"type":["string","null"],"description":"Destination folder (dfo_…). Omit for root."},"filename":{"type":"string","minLength":1,"maxLength":255},"attachment_id":{"type":"string","description":"att_… id or file_url from attachment_upload. Up to 1 GB."}},"required":["account_id","drive_id","filename","attachment_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"id":{"type":"string"},"name":{"type":"string"},"content_type":{"type":"string"},"byte_size":{"type":"integer"},"folder_id":{"type":["string","null"]},"drive_id":{"type":"string"}},"required":["id","name","content_type","byte_size","folder_id","drive_id"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":false,"openWorldHint":false,"readOnlyHint":false},"access_tier":"gated","feature_keys":["files"]},{"name":"drive_folder_list","title":"List Folder Contents","description":"Lists the immediate children (folders + files, both live) of\nthe given folder — or the drive's root when `folder_id` is\nomitted. Each row carries `kind = folder | file`, size /\ncontent_type for files, updated_at, uploader / creator.\nNot recursive — call again for each folder you want to\ndescend into.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"drive_id":{"type":"string"},"folder_id":{"type":"string","description":"Folder prefix ID (dfo_…). Omit to list the drive's root."}},"required":["account_id","drive_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"drive_id":{"type":"string"},"folder_id":{"type":["string","null"],"description":"The folder we listed under, or null for root."},"breadcrumb":{"type":"array","description":"Path from root down to (but not including) the current folder, deepest last.","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}}}},"entries":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"kind":{"type":"string","enum":["folder","file"]},"name":{"type":"string"},"content_type":{"type":["string","null"],"description":"File MIME (null for folders)."},"byte_size":{"type":["integer","null"],"description":"File size in bytes (null for folders)."},"folder_id":{"type":["string","null"],"description":"Parent folder id — matches the request's folder_id."},"uploaded_by":{"type":["object","null"]},"updated_at":{"type":"string","format":"date-time"}},"required":["id","kind","name","content_type","byte_size","folder_id","uploaded_by","updated_at"]}}},"required":["drive_id","folder_id","breadcrumb","entries"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":true},"access_tier":"gated","feature_keys":["files"]},{"name":"drive_folder_save","title":"Create or Update Folder","description":"Linear-style upsert. Omit `id` to create a new folder in the\ngiven drive; pass `id` (dfo_…) to rename or move an existing\none. `parent_id` picks the destination folder (omit for root).\n\nAccess: create requires editor+ on the drive; update requires\neditor+ AND same-drive parent (Pundit `DriveFolderPolicy`).","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"drive_id":{"type":"string","description":"Drive prefix ID. Required on create; ignored on update (folder's drive is fixed)."},"id":{"type":"string","description":"Folder prefix ID (dfo_…). Omit to create."},"name":{"type":"string","maxLength":200},"parent_id":{"type":["string","null"],"description":"Parent folder prefix ID (dfo_…). Pass null to move to root."}},"required":["account_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"id":{"type":"string"},"name":{"type":"string"},"parent_id":{"type":["string","null"]},"drive_id":{"type":"string"},"created":{"type":"boolean"}},"required":["id","name","parent_id","drive_id","created"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":false,"openWorldHint":false,"readOnlyHint":false},"access_tier":"gated","feature_keys":["files"]},{"name":"drive_folder_trash","title":"Move Folder to Trash","description":"Soft-deletes a folder and its entire subtree (all descendant\nfolders + files). Restore via the in-app Trash tab.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"id":{"type":"string","description":"Folder prefix ID (dfo_…)."}},"required":["account_id","id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"id":{"type":"string"},"trashed":{"type":"boolean"}},"required":["id","trashed"],"type":"object"},"annotations":{"destructiveHint":true,"idempotentHint":false,"openWorldHint":false,"readOnlyHint":false},"access_tier":"gated","feature_keys":["files"]},{"name":"drive_get","title":"Get Drive","description":"Returns a single drive's metadata plus the caller's inherited\nworkspace role. Root-level counts (folders + files, live only) are\nincluded so an agent can decide whether to page in.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"drive_id":{"type":"string","description":"Drive prefix ID (drv_…) from drive_list."}},"required":["account_id","drive_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":["string","null"]},"workspace_role":{"type":"string","enum":["member","manager"]},"archived":{"type":"boolean"},"root_folder_count":{"type":"integer","description":"Live folders directly under the root."},"root_file_count":{"type":"integer","description":"Live files directly under the root."},"total_file_count":{"type":"integer","description":"Live files anywhere in the drive."},"created_by":{"type":"object"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["id","name","description","workspace_role","archived","root_folder_count","root_file_count","total_file_count","created_by","created_at","updated_at"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":true},"access_tier":"gated","feature_keys":["files"]},{"name":"drive_link_revoke","title":"Revoke Share Link","description":"Marks the link as revoked. The public URL immediately returns\n410 Gone. Reversible — call `drive_link_save` with the same\n`id` and no revoke bit (there's no `restore` MCP shortcut yet;\nuse the in-app UI or send a follow-up save call).","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"id":{"type":"string"}},"required":["account_id","id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"id":{"type":"string"},"revoked":{"type":"boolean"}},"required":["id","revoked"],"type":"object"},"annotations":{"destructiveHint":true,"idempotentHint":false,"openWorldHint":false,"readOnlyHint":false},"access_tier":"gated","feature_keys":["files"]},{"name":"drive_link_save","title":"Create or Update Share Link","description":"Linear-style upsert. Omit `id` to mint a fresh share link for\nthe given file. Pass `id` (dlk_…) to update expiry or password\non an existing link. Same primitives as the in-app share modal:\n\n- `expires_at` — ISO 8601, date-only, or relative offset\n  (`+7d`, `+2h`). Null / omitted = no expiry.\n- `password` — plaintext; hashed via has_secure_password AND\n  stored plaintext-encrypted so a manager can look it up later.\n  Null / omitted on create = no password. On update, omit to\n  keep existing; pass empty string to clear.\n\nManager on the drive is required (Pundit DriveLinkPolicy).\nReturns the public `/links/:token` URL.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"id":{"type":"string","description":"DriveLink prefix ID (dlk_…). Omit to create."},"file_id":{"type":"string","description":"File prefix ID (dfi_…). Required on create."},"expires_at":{"type":["string","null"],"description":"ISO 8601, date, or relative offset (`+7d`)."},"password":{"type":["string","null"],"description":"Plaintext password. Empty string clears on update."}},"required":["account_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"id":{"type":"string"},"file_id":{"type":"string"},"token":{"type":"string"},"public_url":{"type":"string"},"expires_at":{"type":["string","null"],"format":"date-time"},"password_protected":{"type":"boolean"},"revoked":{"type":"boolean"},"created":{"type":"boolean"}},"required":["id","file_id","token","public_url","expires_at","password_protected","revoked","created"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":false,"openWorldHint":false,"readOnlyHint":false},"access_tier":"gated","feature_keys":["files"]},{"name":"drive_list","title":"List Drives","description":"Lists drives the caller can see in this account, sorted by\n`updated_at DESC`. Archived drives are excluded by default;\nset `include_archived: true` to see them too. Each row carries\nthe caller's inherited workspace role (`member` / `manager`), the file\ncount, and the drive's own metadata.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string","description":"Account prefix ID (acct_…)."},"include_archived":{"type":"boolean","description":"When true, archived drives are included in the result. Default false."}},"required":["account_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"drives":{"type":"array","description":"Drives visible to the caller, sorted updated_at DESC.","items":{"type":"object","properties":{"id":{"type":"string","description":"Drive prefix ID (drv_…) — pass to every other drive_* tool."},"name":{"type":"string"},"description":{"type":["string","null"]},"workspace_role":{"type":"string","enum":["member","manager"]},"file_count":{"type":"integer","description":"Live (non-trashed) file count."},"archived":{"type":"boolean"},"created_by":{"type":"object","properties":{"id":{"type":"string"},"handle":{"type":"string"},"name":{"type":"string"}}},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["id","name","description","workspace_role","file_count","archived","created_by","created_at","updated_at"]}}},"required":["drives"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":true},"access_tier":"gated","feature_keys":["files"]},{"name":"drive_save","title":"Create or Update Drive","description":"Linear-style upsert. Omit `id` to create a new drive in a\nworkspace (the workspace is the mandatory outer access boundary) in this\naccount. Access is inherited immediately from that workspace; the drive\ncreates no separate grant. Pass `id` (drv_…) to rename or re-describe an\nexisting drive. Account admins may pass `workspace_id` while updating\nto move the complete drive. Toggle `archive: true` / `false` to soft-hide\nor restore a drive.\n\nName is unique per workspace (case-insensitive) among active\ndrives; the DB has a `WHERE archived_at IS NULL` unique index\nthat enforces it, so trying to reuse a live drive's name\nreturns a validation error.\n\nAccess (DrivePolicy):\n- Create: any member of the selected workspace.\n- Update / archive: account admin or destination workspace manager.\n- Move to another workspace: account admin only.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"id":{"type":"string","description":"Drive prefix ID (drv_…). Omit to create."},"workspace_id":{"type":"string","description":"Workspace prefix ID (wsp_…) or key. Required on create; admin-only on update."},"name":{"type":"string","maxLength":80},"description":{"type":["string","null"]},"archive":{"type":"boolean","description":"true = archive (soft-hide from lists); false = un-archive. Omit to leave archive state unchanged."}},"required":["account_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"id":{"type":"string"},"workspace_id":{"type":"string"},"name":{"type":"string"},"description":{"type":["string","null"]},"workspace_role":{"type":"string","enum":["member","manager"]},"archived":{"type":"boolean"},"created":{"type":"boolean","description":"true iff this call inserted a fresh drive."},"created_by":{"type":"object"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["id","workspace_id","name","description","workspace_role","archived","created","created_by","created_at","updated_at"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":false,"openWorldHint":false,"readOnlyHint":false},"access_tier":"gated","feature_keys":["files"]},{"name":"drive_search","title":"Search Files in a Drive","description":"Case-insensitive substring match on file names within a single\ndrive. Same query the in-app search box runs. Returns up to\n100 live files sorted by `updated_at DESC`. Does NOT\nsearch folder names or file contents.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"drive_id":{"type":"string"},"q":{"type":"string","minLength":1,"description":"Substring to match on file name. Case-insensitive."}},"required":["account_id","drive_id","q"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"drive_id":{"type":"string"},"q":{"type":"string"},"count":{"type":"integer"},"truncated":{"type":"boolean","description":"True when the result was capped at 100 rows."},"results":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"content_type":{"type":["string","null"]},"byte_size":{"type":"integer"},"folder_id":{"type":["string","null"]},"path":{"type":"string"},"updated_at":{"type":"string","format":"date-time"}}}}},"required":["drive_id","q","count","truncated","results"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":true},"access_tier":"gated","feature_keys":["files"]},{"name":"email_account_list","title":"List Email Accounts","description":"Lists all Gmail accounts the caller has connected in this\noona account, with each account's user-defined labels\nand current unread-thread count. Use this first to discover\naccount IDs (`mail_…`) and label IDs (`elbl_…`) before\ncalling other email tools.\n\nSystem labels are not returned per-account but can be used\ndirectly with their well-known IDs: `INBOX`, `TRASH`,\n`SPAM`, `STARRED`, `UNREAD`, `IMPORTANT`, `CHAT`, `DRAFT`,\n`SENT`.\n\nAccount-scoped: the same Gmail address connected in\nanother account is a different `mail_…` ID and is\ninvisible from here.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string","description":"Account prefix ID (acct_…)."}},"required":["account_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"accounts":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Email-account prefix ID (mail_…)."},"email_address":{"type":"string"},"display_name":{"type":["string","null"]},"status":{"type":"string","enum":["connecting","active","error","paused","disconnected"]},"can_organize":{"type":"boolean"},"can_send":{"type":"boolean"},"send_confirmation_required":{"type":"boolean"},"color_hex":{"type":["string","null"]},"unread_count":{"type":"integer","description":"Threads with at least one unread message."},"labels":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Label prefix ID (elbl_…)."},"name":{"type":"string"},"kind":{"type":"string","enum":["user","system"]},"color_hex":{"type":["string","null"]}},"required":["id","name","kind"]}}},"required":["id","email_address","status","unread_count","labels"]}}},"required":["accounts"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":true},"access_tier":"gated","feature_keys":["email"]},{"name":"email_attachment_url","title":"Get Email Attachment Download URL","description":"Returns a short-lived signed URL (~15 min) for downloading\nan email attachment. The attachment's account binding is\ninferred from the `eatt_…` ID.\n\nEmail attachments are lazy: the row is created at\nheader-sync time but the bytes are pulled on demand. If\nthe blob isn't yet stored locally, this tool fetches it\nfrom Gmail synchronously before returning the URL.\n\nThe URL is fine to pass to any HTTP client — it carries\nits own signature and does not need an Authorization\nheader.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string","description":"Account prefix ID (acct_…)."},"attachment_id":{"type":"string","description":"Email attachment prefix ID (eatt_…) from email_thread_get FULL_CONTENT."}},"required":["account_id","attachment_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"url":{"type":"string","format":"uri","description":"Signed download URL, valid 15 minutes."},"expires_at":{"type":"string","format":"date-time"},"filename":{"type":"string"},"content_type":{"type":["string","null"]},"size_bytes":{"type":["integer","null"]}},"required":["url","expires_at","filename"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":true},"access_tier":"gated","feature_keys":["email"]},{"name":"email_convert_to_task","title":"Convert Email to Task","description":"Creates a Task from an email and links the two so the\nconversion is traceable and idempotent.\n\nPass exactly one of `message_id` (`emsg_…`) or `thread_id`\n(`ethr_…`); for a thread the latest message is used as the\nanchor. `workspace_id` is the destination workspace (prefix `wsp_…`\nor KEY like `ENG`); `project_id` (`proj_…` or slug) is\noptional and must belong to that workspace.\n\nDefaults: `title` = the email subject; the task description\nis seeded from the email body (override with `description`,\nMarkdown). `assignee` is a `@handle` or user prefix.\n\n`link_kind` is `created_from` (default — this task was made\nfrom the email) or `referenced_in`. Idempotent: if the\nsource is already linked with the same `link_kind`, the\nexisting task is returned with `created: false` and no new\ntask is made.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string","description":"Account prefix ID (acct_…)."},"message_id":{"type":"string","description":"Source message (emsg_…). Provide this OR thread_id."},"thread_id":{"type":"string","description":"Source thread (ethr_…); its latest message is used. Provide this OR message_id."},"workspace_id":{"type":"string","description":"Destination workspace prefix ID (wsp_…) or KEY (e.g. ENG)."},"project_id":{"type":"string","description":"Optional project (proj_… or slug); must belong to the workspace."},"title":{"type":"string","description":"Task title. Defaults to the email subject."},"description":{"type":"string","description":"Task description in Markdown. Defaults to the email body."},"assignee":{"type":"string","description":"Assignee @handle or user prefix ID."},"link_kind":{"type":"string","enum":["created_from","referenced_in"],"description":"Provenance link kind. Default created_from."}},"required":["account_id","workspace_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"task":{"type":"object","properties":{"id":{"type":"string"},"key":{"type":"string"},"url":{"type":"string"}},"required":["id","key","url"]},"link":{"type":"object","properties":{"id":{"type":"string"},"kind":{"type":"string"}},"required":["id","kind"]},"created":{"type":"boolean","description":"false when an existing link/task was returned (idempotent)."}},"required":["task","link","created"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":false},"access_tier":"gated","feature_keys":["email"]},{"name":"email_send","title":"Send Email","description":"Sends an email from one of the caller's connected Gmail\naccounts in this account. Covers five modes via\nparameters — they're mutually exclusive:\n\n- **New** (default): omit `reply_to_message_id`,\n  `forward_of`, and `redirect_of`.\n- **Reply**: set `reply_to_message_id` to an `emsg_…`. The\n  subject is auto-prefixed with `Re:` if absent, threading\n  headers (`In-Reply-To`, `References`) are populated, and\n  the message stays in the original Gmail conversation.\n  The original is auto-quoted below your body — write only\n  your own reply, not the citation.\n- **Reply-all**: same as reply, plus set `reply_all: true`\n  to copy the original `To` + `Cc` (minus your own\n  addresses) into the outgoing `Cc`.\n- **Forward**: set `forward_of` to an `emsg_…`. Subject\n  gets `Fwd:` prefix, the original is quoted below your\n  body, original attachments are NOT auto-carried (re-\n  attach explicitly via `attachment_ids` if needed).\n- **Redirect**: set `redirect_of` to an `emsg_…`. Body is\n  NOT taken from `body_markdown`; the original message is\n  forwarded verbatim with optional `comment` rendered in\n  an attribution box. `Reply-To` is set to the original\n  sender so the recipient can reply directly to them.\n  `subject` / `body_markdown` are ignored in this mode.\n\n`as_draft: true` saves to the sender's Drafts instead of\nsending. Works with new/reply/forward; not with redirect.\n\nBody is Markdown — server renders to HTML (and a plain-\ntext fallback) so the recipient sees formatting and\nclickable links. Use standard GFM (headings, lists, bold,\nitalic, links, code).\n\nAttachments: pass `attachment_ids` — handles from\n`attachment_upload` (att_… ids or file_urls).\nCombined size <= 25 MB (Gmail's limit).\n\nOn success returns `{ message_id, thread_id }` (live send)\nor `{ draft_id }` (when `as_draft: true`).\n\nGating: if the mailbox owner enabled \"Require confirmation\nfor agent send\", a live send is held as a draft and returns\n`{ confirmation_required: true, draft_id }` instead of\nsending — a human approves it later. Otherwise, direct live\nsends are rate-limited (50/hour per user); over the cap\nreturns `{ rate_limited: true, retry_after }`. `as_draft`\nand confirmation-held sends do not count against the cap\n(held sends are governed by human approval instead).","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string","description":"Account prefix ID (acct_…)."},"from_account_id":{"type":"string","description":"Sender mail account prefix ID (mail_…). Discover via email_account_list."},"to":{"type":"array","items":{"type":"string"},"description":"Primary recipients. Plain addresses only — no \"Name <email>\"."},"cc":{"type":"array","items":{"type":"string"},"description":"Cc recipients. Plain addresses only."},"bcc":{"type":"array","items":{"type":"string"},"description":"Bcc recipients. Plain addresses only."},"subject":{"type":"string","description":"Subject line. Auto-prefixed with Re:/Fwd: in reply/forward modes if absent. Ignored in redirect mode."},"body_markdown":{"type":"string","description":"GFM Markdown body. Server renders to HTML; plain text is auto-derived. Ignored in redirect mode."},"reply_to_message_id":{"type":"string","description":"Message prefix ID (emsg_…) to reply to. Exclusive with forward_of/redirect_of."},"reply_all":{"type":"boolean","description":"Reply-mode only: include original To+Cc (minus self) in outgoing Cc."},"forward_of":{"type":"string","description":"Message prefix ID (emsg_…) to forward. Exclusive with reply_to_message_id/redirect_of."},"redirect_of":{"type":"string","description":"Message prefix ID (emsg_…) to redirect. Exclusive with reply_to_message_id/forward_of."},"comment":{"type":"string","description":"Redirect mode only: short note rendered in an attribution box above the forwarded body."},"attachment_ids":{"type":"array","items":{"type":"string"},"description":"Attachment handles from attachment_upload — att_… ids or file_urls."},"as_draft":{"type":"boolean","description":"Save to Drafts instead of sending. Default false. Not compatible with redirect."}},"required":["account_id","from_account_id","to"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"message_id":{"type":["string","null"],"description":"Set when the message was sent."},"thread_id":{"type":["string","null"],"description":"Set when the message was sent."},"draft_id":{"type":["string","null"],"description":"Set when as_draft was true, or when a live send was held for confirmation."},"mode":{"type":"string","enum":["new","reply","reply_all","forward","redirect"]},"confirmation_required":{"type":"boolean","description":"ENG-1218: true when the send was held as a draft for human approval instead of sent."},"rate_limited":{"type":"boolean","description":"ENG-1218: true when the hourly send rate limit was hit; nothing was sent."},"retry_after":{"type":["integer","null"],"description":"Seconds to wait before retrying, when rate_limited."}},"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":false,"openWorldHint":true,"readOnlyHint":false},"access_tier":"gated","feature_keys":["email"]},{"name":"email_send_no_reply","title":"Send No-Reply Email","description":"Sends a single transactional email from the system no-reply\naddress (`oona <no-reply@mailer.oona.ai>`). Use this\nfor notifications and alerts that do NOT expect a reply —\nreport finished, run completed, threshold crossed. For\nanything where the recipient might reply, use `email_send`\nfrom a connected Gmail mailbox instead.\n\nThe sender address is fixed by app config and is NOT\noverridable. The `from_name` parameter only changes the\ndisplay name shown next to it (e.g. `\"Reports\" <no-reply@…>`).\n\nRecipients (`to` / `cc` / `bcc`) are passed as\ncomma-separated strings — `\"a@x.com, b@x.com\"`. At least\none `to` is required.\n\nBody: at least one of `text_content` or `html_content` must\nbe present. If only one is given the mail is single-part;\nif both are given it goes out as multipart (text + html).\nUnlike `email_send`, neither body is Markdown — the agent\nprovides each format verbatim.\n\nAttachments: optional inline base64 list, each item\n`{filename, content (base64), content_type?}`. Combined size\n≤ 10 MB across the whole email. `content_type` defaults to\n`application/octet-stream` when omitted.\n\nOn success returns `{ sent: true, from, subject, to_count,\ncc_count, bcc_count, attachment_count }`.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string","description":"Account prefix ID (acct_…)."},"to":{"type":"string","description":"Primary recipients, comma-separated. At least one required."},"cc":{"type":"string","description":"Cc recipients, comma-separated. Optional."},"bcc":{"type":"string","description":"Bcc recipients, comma-separated. Optional."},"subject":{"type":"string","description":"Subject line."},"text_content":{"type":"string","description":"Plain-text body. At least one of text_content / html_content is required."},"html_content":{"type":"string","description":"HTML body. At least one of text_content / html_content is required."},"from_name":{"type":"string","description":"Display name shown in the From header. The address itself stays the configured no-reply."},"attachments":{"type":"array","description":"Optional inline attachments. Combined size ≤ 10 MB across the whole email.","items":{"type":"object","properties":{"filename":{"type":"string","description":"Filename shown in the mail."},"content":{"type":"string","description":"Base64-encoded file bytes."},"content_type":{"type":"string","description":"MIME type. Defaults to application/octet-stream."}},"required":["filename","content"]}}},"required":["account_id","to","subject"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"sent":{"type":"boolean"},"from":{"type":"string","description":"The From header that was used (incl. display name)."},"subject":{"type":"string"},"to_count":{"type":"integer"},"cc_count":{"type":"integer"},"bcc_count":{"type":"integer"},"attachment_count":{"type":"integer"}},"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":false,"openWorldHint":true,"readOnlyHint":false},"access_tier":"gated","feature_keys":["email"]},{"name":"email_share_to_chat","title":"Share Email to Chat","description":"Posts an email into a chat channel or DM so the workspace can see\nit without leaving chat, and links the two for traceability.\n\nPass exactly one of `message_id` (`emsg_…`) or `thread_id`\n(`ethr_…`); for a thread the latest message is shared. Pass\nexactly one target: `channel_id` (`chan_…` from\nchat_list_channels) or `dm_with_user` (a `@handle` / user\nprefix — starts-or-finds the 1:1 DM).\n\nThe posted message is authored by you: an optional `comment`\non top, then a quote block (sender / subject / snippet) unless\n`include_quote` is false, and the email's attachments unless\n`include_attachments` is false (default true for both).\n\nYou must have post access to the target channel (membership,\nor admin/employer reach). Idempotent per (email, channel): if\nthe email is already shared into that channel the existing\nchat message is returned with `created: false` — a retry won't\ndouble-post.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string","description":"Account prefix ID (acct_…)."},"message_id":{"type":"string","description":"Source message (emsg_…). Provide this OR thread_id."},"thread_id":{"type":"string","description":"Source thread (ethr_…); its latest message is shared. Provide this OR message_id."},"channel_id":{"type":"string","description":"Target channel (chan_…). Provide this OR dm_with_user."},"dm_with_user":{"type":"string","description":"Target DM partner: @handle or user prefix ID. Starts-or-finds the 1:1 DM. Provide this OR channel_id."},"comment":{"type":"string","description":"Optional note posted above the email quote."},"include_attachments":{"type":"boolean","description":"Re-attach the email's files to the chat message. Default true."},"include_quote":{"type":"boolean","description":"Include the From / Subject / snippet quote block. Default true."}},"required":["account_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"chat_message":{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string"}},"required":["id","url"]},"share_link_id":{"type":"string","description":"The EmailChatShare prefix ID (ecsh_…)."},"created":{"type":"boolean","description":"false when an existing share was returned (idempotent re-share)."}},"required":["chat_message","share_link_id","created"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":false},"access_tier":"gated","feature_keys":["email"]},{"name":"email_thread_get","title":"Get Email Thread","description":"Retrieves a specific email thread by its prefixed ID\n(`ethr_…`) including its messages, ordered oldest →\nnewest. The thread's account binding is inferred from the\nID, so no `account_id` is needed here beyond the account\ncontext.\n\n`message_format` controls how much per-message detail you\nget:\n\n- `FULL_CONTENT` (default) — snippet, headers, plain-text\n  and HTML body, and the list of attachments (each with\n  its `eatt_…` ID and metadata). Use this when you need\n  to read or quote the content.\n- `MINIMAL` — snippet plus the key headers (Subject, From,\n  To, Cc, Date) only; body content and attachment metadata\n  are omitted. Use this for cheap thread previews.\n\nBody content arrives as plain text (`body_text`) and HTML\n(`body_html`). Plain text is usually what an agent should\nreason over; the HTML is included for completeness.\n\nTo download an attachment's bytes, call\n`email_attachment_url` with the `eatt_…` ID returned here.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string","description":"Account prefix ID (acct_…)."},"thread_id":{"type":"string","description":"Thread prefix ID (ethr_…) from email_thread_search."},"message_format":{"type":"string","enum":["FULL_CONTENT","MINIMAL"],"description":"Per-message detail level. Default FULL_CONTENT."}},"required":["account_id","thread_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"thread":{"type":"object","properties":{"id":{"type":"string"},"account_id":{"type":"string"},"subject":{"type":["string","null"]},"snippet":{"type":["string","null"]},"participants":{"type":"array","items":{"type":"object"}},"message_count":{"type":"integer"},"last_message_at":{"type":["string","null"],"format":"date-time"},"is_unread":{"type":"boolean"},"is_starred":{"type":"boolean"},"has_attachments":{"type":"boolean"},"messages":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"from":{"type":["object","null"]},"to":{"type":"array","items":{"type":"object"}},"cc":{"type":"array","items":{"type":"object"}},"bcc":{"type":"array","items":{"type":"object"}},"subject":{"type":["string","null"]},"snippet":{"type":["string","null"]},"date":{"type":["string","null"],"format":"date-time"},"is_unread":{"type":"boolean"},"is_starred":{"type":"boolean"},"is_draft":{"type":"boolean"},"is_sent":{"type":"boolean"},"labels":{"type":"array","items":{"type":"string"}},"body_text":{"type":["string","null"],"description":"Only in FULL_CONTENT."},"body_html":{"type":["string","null"],"description":"Only in FULL_CONTENT."},"attachments":{"type":"array","description":"Only in FULL_CONTENT. Use email_attachment_url to download.","items":{"type":"object","properties":{"id":{"type":"string"},"filename":{"type":"string"},"content_type":{"type":["string","null"]},"size_bytes":{"type":["integer","null"]},"is_inline":{"type":"boolean"}}}}},"required":["id","from","subject","snippet","date","is_unread","is_starred","is_draft","is_sent","labels"]}}},"required":["id","account_id","subject","snippet","message_count","last_message_at","is_unread","is_starred","has_attachments","messages"]}},"required":["thread"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":true},"access_tier":"gated","feature_keys":["email"]},{"name":"email_thread_modify","title":"Modify Email Thread","description":"Modifies a thread's state: applies / removes labels, marks\nread or unread, stars / un-stars, moves to or from trash.\nChanges are pushed to Gmail (so they sync to the user's\nother clients) and the local mirror is updated to match.\n\nConvenience shortcuts:\n\n- **Archive** = `remove_labels: [\"INBOX\"]`\n- **Mark thread read** = `read: true`\n- **Star** = `starred: true` (same as adding `STARRED`)\n- **Move to spam** = `add_labels: [\"SPAM\"]`\n\nLabel IDs accept either Gmail's system well-known IDs\n(`INBOX`, `UNREAD`, `STARRED`, `IMPORTANT`, `TRASH`,\n`SPAM`, `DRAFT`, `SENT`, `CHAT`) or a user label's prefix\nID (`elbl_…`) discovered via `email_account_list`.\n\nAccount binding is inferred from the thread ID — no\n`from_account_id` is needed.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string","description":"Account prefix ID (acct_…)."},"thread_id":{"type":"string","description":"Thread prefix ID (ethr_…)."},"add_labels":{"type":"array","items":{"type":"string"},"description":"Label IDs to add. System well-knowns or elbl_… IDs."},"remove_labels":{"type":"array","items":{"type":"string"},"description":"Label IDs to remove. Same format as add_labels."},"read":{"type":"boolean","description":"true → remove UNREAD on every message; false → mark all unread."},"starred":{"type":"boolean","description":"true → add STARRED; false → remove STARRED."},"trashed":{"type":"boolean","description":"true → move to trash; false → restore from trash."}},"required":["account_id","thread_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"ok":{"type":"boolean"},"thread":{"type":"object","description":"MINIMAL-format thread state after the mutation (no per-message bodies/attachments).","properties":{"id":{"type":"string"},"account_id":{"type":"string"},"subject":{"type":["string","null"]},"snippet":{"type":["string","null"]},"message_count":{"type":"integer"},"last_message_at":{"type":["string","null"],"format":"date-time"},"is_unread":{"type":"boolean"},"is_starred":{"type":"boolean"},"has_attachments":{"type":"boolean"}}}},"required":["ok","thread"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":false},"access_tier":"gated","feature_keys":["email"]},{"name":"email_thread_search","title":"Search Email Threads","description":"Lists email threads from the caller's connected Gmail\naccounts in this oona account.\n\nFilters via Gmail's native query syntax — the same\noperators that work in Gmail web search:\n\n- **Sender/recipient:** `from:`, `to:`, `cc:`, `bcc:`,\n  `deliveredto:`, `list:`\n- **Time:** `after:YYYY/MM/DD`, `before:YYYY/MM/DD`,\n  `newer:`, `older:`, `older_than:1y`, `newer_than:7d`\n- **Content:** `subject:`, `has:attachment`, `filename:`,\n  `\"exact phrase\"`, `+exact`, `rfc822msgid:`, `AROUND`\n- **Status/location:** `is:unread`, `is:starred`,\n  `is:important`, `in:inbox|sent|drafts|trash|spam|anywhere`,\n  `category:primary|social|promotions|updates|forums|reservations|purchases`\n- **Labels:** `label:Newsletter` (use the label name as\n  shown to the user)\n- **Size:** `larger:10M`, `smaller:500K`\n- **Logic:** `AND`, `OR`, `-exclude`, `( )` grouping\n\nExamples:\n- `\"is:unread newer_than:7d\"`\n- `\"from:finance@versacommerce.de subject:invoice\"`\n- `\"has:attachment in:inbox -from:no-reply\"`\n\nReturns thread headers + a short snippet. Use\n`email_thread_get` with a returned `ethr_…` ID to read\nthe messages.\n\nBy default searches across **all** connected accounts in\nthe account; pass `account_ids` to narrow. Pagination\nvia `page_size` (max 50) and `page_token`.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string","description":"Account prefix ID (acct_…)."},"account_ids":{"type":"array","items":{"type":"string"},"description":"Restrict to specific Gmail accounts (mail_… from email_account_list). Default: all live accounts."},"query":{"type":"string","description":"Gmail query syntax. Empty = list everything except spam/trash."},"include_trash":{"type":"boolean","description":"Include threads from TRASH. Default false."},"page_size":{"type":"integer","minimum":1,"maximum":50,"description":"Default 20, max 50."},"page_token":{"type":"string","description":"Opaque cursor from a previous response's next_page_token."}},"required":["account_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"threads":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"account_id":{"type":"string"},"subject":{"type":["string","null"]},"snippet":{"type":["string","null"]},"participants":{"type":"array","items":{"type":"object"}},"message_count":{"type":"integer"},"last_message_at":{"type":["string","null"],"format":"date-time"},"is_unread":{"type":"boolean"},"is_starred":{"type":"boolean"},"has_attachments":{"type":"boolean"}},"required":["id","account_id","subject","message_count","is_unread","is_starred"]}},"next_page_token":{"type":["string","null"]}},"required":["threads"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":true},"access_tier":"gated","feature_keys":["email"]},{"name":"group_get","title":"Get Group","description":"Returns one group's metadata + every member. Useful before\nmaking a follow-up `group_member_add` / `group_member_remove`\ncall so the agent can confirm the current roster.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"id":{"type":"string","description":"Group prefix ID (grp_…)."}},"required":["account_id","id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"group":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":["string","null"]},"archived":{"type":"boolean"},"created_at":{"type":"string","format":"date-time"},"members":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"User prefix ID or @handle."},"handle":{"type":["string","null"]},"name":{"type":"string"}},"required":["id","name"]}}},"required":["id","name","archived","created_at","members"]}},"required":["group"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":true},"access_tier":"gated","feature_keys":["none"]},{"name":"group_list","title":"List Groups","description":"Lists member groups in the account. Groups are a primitive\nfor scoping (channel access, document sharing, project\nvisibility) — no ACL surfaces consume them yet, but the\nIDs returned here are stable and safe to attach to future\npermission rows.\n\nSoft-deleted (archived) groups are excluded by default;\npass `include_archived: true` to surface them as well.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"include_archived":{"type":"boolean","default":false}},"required":["account_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"groups":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Group prefix ID (grp_…)."},"name":{"type":"string"},"description":{"type":["string","null"]},"member_count":{"type":"integer"},"archived":{"type":"boolean"},"created_at":{"type":"string","format":"date-time"}},"required":["id","name","member_count","archived","created_at"]}}},"required":["groups"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":true},"access_tier":"gated","feature_keys":["none"]},{"name":"group_member_add","title":"Add Group Member","description":"Adds `user` to `group`. Idempotent: a re-add returns the\nexisting row unchanged. Refuses to add a user from a\ndifferent account.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"group_id":{"type":"string","description":"Group prefix ID (grp_…)."},"user":{"type":"string","description":"User prefix ID or @handle."}},"required":["account_id","group_id","user"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"group_id":{"type":"string"},"user_id":{"type":"string"},"added":{"type":"boolean","description":"false when the user was already a member."}},"required":["group_id","user_id","added"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":false},"access_tier":"gated","feature_keys":["none"]},{"name":"group_member_remove","title":"Remove Group Member","description":"Removes `user` from `group`. Idempotent: removing a\nnon-member returns `removed: false` without erroring.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"group_id":{"type":"string"},"user":{"type":"string","description":"User prefix ID or @handle."}},"required":["account_id","group_id","user"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"group_id":{"type":"string"},"user_id":{"type":"string"},"removed":{"type":"boolean"}},"required":["group_id","user_id","removed"],"type":"object"},"annotations":{"destructiveHint":true,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":false},"access_tier":"gated","feature_keys":["none"]},{"name":"group_save","title":"Create or Update Group","description":"Upserts a member group. On create, name is required; on\nupdate, only the keys you pass are changed (name +\ndescription + archived). Name must be unique per account\namong active groups — archiving a group frees its name\nfor reuse.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"id":{"type":"string","description":"Group prefix ID. Omit to create."},"name":{"type":"string","description":"Required on create."},"description":{"type":["string","null"]},"archived":{"type":"boolean","description":"true → archive; false → unarchive."}},"required":["account_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"group":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":["string","null"]},"archived":{"type":"boolean"}},"required":["id","name","archived"]}},"required":["group"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":false,"openWorldHint":false,"readOnlyHint":false},"access_tier":"gated","feature_keys":["none"]},{"name":"http_request","title":"HTTP Request","description":"Call an external HTTP service with method, URL, headers and an optional body.\nPut authentication and Content-Type in headers, e.g. {\"Authorization\":\"Bearer …\",\"Content-Type\":\"application/json\"}.\nThe body is a string; serialize JSON yourself. Returns status, response headers\n(arrays of values), body and body_encoding (utf-8 or base64 for binary).\nHTTP error statuses are returned normally. Redirects are NOT followed: inspect\nLocation before making a separate request; never forward credentials blindly.\nPublic Internet endpoints only. Request/response body limit: 1 MB; timeout: 30s.\nRequests are never automatically retried. A timeout may still mean a mutation succeeded.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"method":{"type":"string","enum":["GET","HEAD","POST","PUT","PATCH","DELETE","OPTIONS"]},"url":{"type":"string","description":"Absolute HTTP(S) URL."},"headers":{"type":"object","additionalProperties":{"type":"string"}},"body":{"type":"string","description":"Raw request body, e.g. serialized JSON."}},"required":["account_id","method","url"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"status":{"type":"integer"},"headers":{"type":"object","additionalProperties":{"type":"array","items":{"type":"string"}}},"body":{"type":"string"},"body_encoding":{"type":"string","enum":["utf-8","base64"]}},"required":["status","headers","body","body_encoding"],"type":"object"},"annotations":{"destructiveHint":true,"idempotentHint":false,"openWorldHint":true,"readOnlyHint":false},"access_tier":"gated","feature_keys":["none"]},{"name":"label_list","title":"List Labels","description":"Lists labels in the account, alphabetically. Labels are\nworkspace-scoped — pass `workspace_id` to narrow to one workspace. The same\nname may exist in several workspaces; clients should disambiguate\nvia the returned `workspace` block or the label's prefix id.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string","description":"Account prefix ID (acct_…)."},"workspace_id":{"type":"string","description":"Optional workspace prefix ID or key. Narrows results to one workspace."}},"required":["account_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"labels":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"color":{"type":"string"},"description":{"type":["string","null"]},"workspace":{"type":"object","properties":{"id":{"type":"string"},"key":{"type":"string"},"name":{"type":"string"}},"required":["id","key","name"]}},"required":["id","name","color","workspace"]}}},"required":["labels"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":true},"access_tier":"gated","feature_keys":["projects_tasks"]},{"name":"project_activities","title":"Project Activities","description":"Unified recent-activity feed — answers\n\"what happened on this project / task / workspace lately?\"\nwithout enumerating every task.\n\nMerges four sources, sorted newest-first:\n  - project_event   (created / status_changed / target_changed /\n                     lead_changed / name_changed)\n  - project_update  (status updates the workspace posts on the project\n                     Activity tab; includes health + body)\n  - task_event      (task status / assignee / priority / due /\n                     label / project / subtask changes)\n  - task_comment    (comments on tasks within the project)\n\nDefault window: last 30 days, newest 50 entries.\n\nScoping (at least one of these is required):\n  - project_id  proj_… prefix or slug — scope to one project\n                (the primary mode; matches the tool's goal).\n  - workspace_id     workspace prefix or key (ENG) — scope to all the\n                workspace's projects.\n  - task_id     task_… prefix or KEY-N — drill into one task's\n                events + comments.\n\nModifiers (all optional):\n  - kinds       array, any of project_event / project_update /\n                task_event / task_comment.\n  - created_at  ISO 8601 timestamp (2026-05-01T00:00:00Z) OR\n                ISO 8601 duration (-P7D = last 7 days, -P1D =\n                last 24h). Lower bound on created_at.\n  - cursor      opaque, from a previous response's next_cursor.\n  - limit       1-250, default 50.\n\nPagination: pass `next_cursor` from a previous response to fetch\nthe next older page. Per-row `id` is the prefix id of the\nunderlying record (pa_/pu_/act_/cmt_) and the `url` field is a\npaste-able web URL.\n\nAccess: only entries from projects the caller can read are\nreturned (admin/employer see all account projects; regular\nmembers see their workspaces' projects plus projects they lead).","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"project_id":{"type":"string","description":"Project prefix ID (proj_…) or slug."},"workspace_id":{"type":"string","description":"Workspace prefix ID or key (e.g. ENG)."},"task_id":{"type":"string","description":"Task prefix ID (task_…) or issue key (e.g. ENG-3) — refines to one task."},"kinds":{"type":"array","items":{"type":"string","enum":["project_event","project_update","task_event","task_comment"]},"description":"Subset of activity sources to include. Defaults to all four."},"created_at":{"type":"string","description":"Lower bound on created_at. ISO 8601 timestamp or ISO duration (-P7D, -P1D)."},"cursor":{"type":"string","description":"Opaque cursor from a previous response's next_cursor."},"limit":{"type":"integer","default":50,"description":"Max entries (default 50, max 250)."}},"required":["account_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"events":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"kind":{"type":"string","enum":["project_event","project_update","task_event","task_comment"]},"event":{"type":["string","null"]},"created_at":{"type":"string","format":"date-time"},"actor":{"type":["object","null"]},"project":{"type":["object","null"],"description":"Null only for events of orphaned tasks (project deleted via dependent: :nullify)."},"task":{"type":["object","null"]},"payload":{"type":["object","null"]},"body_markdown":{"type":["string","null"]},"health":{"type":["string","null"]},"url":{"type":"string"}},"required":["id","kind","created_at","url"]}},"next_cursor":{"type":["string","null"]}},"required":["events"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":true},"access_tier":"gated","feature_keys":["projects_tasks"]},{"name":"project_get","title":"Get Project","description":"Fetches a single project including the latest update body,\nmember list, and computed progress. Description is returned in\nMarkdown so agents can read + diff it; pair with `project_save`\nwhen writing back. The returned `project.id` is the canonical\n`proj_…` prefix ID — round-trip it through `project_save`,\n`task_save({project_id: …})`, or `project_update_save`.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"id":{"type":"string","description":"Project prefix ID (proj_…) or slug."}},"required":["account_id","id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"project":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name"]}},"required":["project"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":true},"access_tier":"gated","feature_keys":["projects_tasks"]},{"name":"project_list","title":"List Projects","description":"Lists projects the caller can read in the account. Each row\nincludes the project's `proj_…` prefix ID — pass it back to\n`project_get`, `task_save({project_id: …})`, etc. Filter by\n`workspace_id`, status (`backlog | planned | in_progress | paused |\ncompleted | cancelled`), `priority` (`urgent | high | medium |\nlow | no_priority`), and `archived` (defaults to false).\nSorted by name. `progress_ratio` is computed live from\n`completed_tasks / total_tasks`.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string","description":"Account prefix ID."},"workspace_id":{"type":"string","description":"Workspace prefix ID or key (e.g. ENG)."},"status":{"type":"string","description":"Project status enum key."},"priority":{"type":"string","description":"Priority enum key."},"archived":{"type":"boolean","description":"Include archived projects (default false)."},"query":{"type":"string","description":"Substring match on name or summary."}},"required":["account_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"projects":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name"]}}},"required":["projects"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":true},"access_tier":"gated","feature_keys":["projects_tasks"]},{"name":"project_save","title":"Create or Update Project","description":"Linear-style upsert. Pass `id` to update; omit to create. Description accepts Markdown and is converted to Tiptap JSON.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"id":{"type":"string","description":"Project prefix ID (proj_…) or slug. Omit to create."},"workspace_id":{"type":"string","description":"Required on create. Prefix or key."},"name":{"type":"string"},"summary":{"type":["string","null"]},"description_markdown":{"type":["string","null"]},"status":{"type":"string"},"priority":{"type":"string"},"icon_emoji":{"type":["string","null"],"description":"Single unicode emoji glyph (e.g. \"🚀\"). The common `:shortcode:` aliases (`:rocket:`, `:fire:`, `:white_check_mark:`, …) are also accepted and converted to the matching glyph at save time. Pass an empty string to clear."},"color":{"type":"string"},"target_on":{"type":["string","null"]},"start_on":{"type":["string","null"]},"lead":{"type":["string","null"],"description":"User prefix or @handle."}},"required":["account_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"project":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name"]}},"required":["project"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":false,"openWorldHint":false,"readOnlyHint":false},"access_tier":"gated","feature_keys":["projects_tasks"]},{"name":"project_update_save","title":"Post a Project Update","description":"Posts a status update on a project (Linear's `save_status_update`).\nOptional `health` records the project's health: pass one of\n`on_track | at_risk | off_track`, or omit for no health change.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"project_id":{"type":"string","description":"Project prefix ID (proj_…) or slug."},"body":{"type":"string","description":"Update body (plain text or Markdown)."},"health":{"type":["string","null"],"description":"on_track, at_risk, or off_track. Optional."}},"required":["account_id","project_id","body"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"update":{"type":"object","properties":{"id":{"type":"string"},"body":{"type":"string"}},"required":["id","body"]}},"required":["update"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":false,"openWorldHint":false,"readOnlyHint":false},"access_tier":"gated","feature_keys":["projects_tasks"]},{"name":"roadmap_activities","title":"Roadmap Activity Feed","description":"Returns the reverse-chronological activity feed for a roadmap.\nBoth roadmap-level events (created / title_changed /\ndescription_changed / archived / unarchived) and entry-level\nevents (entry_created / entry_title_changed /\nentry_status_changed / entry_dates_changed / entry_destroyed /\nentry_project_linked / entry_project_unlinked) flow into the\nsame feed, ordered newest first.\n\n`payload` shape depends on the event:\n- `title_changed`, `entry_title_changed`: `{from, to}`\n- `entry_status_changed`: `{from, to}` (status names)\n- `entry_dates_changed`: `{starts_on: {from,to}, due_on: {from,to}}`\n- `entry_project_linked` / `entry_project_unlinked`:\n  `{project_id, project_name}` (denormalised so the log\n  survives project renames)\n- `entry_created`: `{title}`\n- Other events carry an empty or minimal payload.\n\n`limit` defaults to 50, clamped to [1, 200].","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"roadmap_id":{"type":"string","description":"Roadmap prefix ID (rmap_…)."},"limit":{"type":"integer","description":"Number of rows to return. Default 50, clamped to [1, 200]."}},"required":["account_id","roadmap_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"activities":{"type":"array","description":"Newest first.","items":{"type":"object","properties":{"id":{"type":"string","description":"ra_…"},"event":{"type":"string","description":"Event name; see the description for the full list."},"payload":{"type":["object","null"],"description":"Event-specific data; shape depends on event."},"user":{"type":["object","null"],"description":"Actor. Null for system events.","properties":{"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name"]},"roadmap_entry_id":{"type":["string","null"],"description":"Set for entry-level events; null for roadmap-level events."},"created_at":{"type":"string","description":"ISO 8601."}},"required":["id","event","created_at"]}}},"required":["activities"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":true},"access_tier":"gated","feature_keys":["projects_tasks"]},{"name":"roadmap_entry_destroy","title":"Delete Roadmap Entry","description":"Permanently deletes a roadmap entry. All of its project links\ngo with it. An `entry_destroyed` activity row is written to\nthe parent roadmap's feed so the deletion remains auditable\nvia `roadmap_activities`.\n\nTwo-step confirmation (deletion is not silent): the first call\n— with `confirm` omitted or false — deletes NOTHING and\nreturns a preview (`confirm_required: true`) naming the entry.\nRepeat with `confirm: true` to actually delete it. Surface the\npreview to the user and get their go-ahead before confirming.\n\nDestructive and NOT idempotent — once confirmed, calling it\nagain with the same id returns `not found or not accessible`.\nPrefer setting `status: cancelled` via `roadmap_entry_save`\nwhen you only want to mark work as discarded but keep the\nhistorical record.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"id":{"type":"string","description":"Entry prefix ID (rent_…)."},"confirm":{"type":"boolean","description":"Must be true to delete. Omit/false returns a dry-run preview and deletes nothing."}},"required":["account_id","id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"deleted":{"type":"boolean","description":"True once deleted; false on a preview."},"confirm_required":{"type":"boolean","description":"True on a preview — call again with confirm: true to delete."},"id":{"type":"string","description":"The entry's prefix ID, echoed back."},"title":{"type":"string","description":"The entry's title (so the preview is human-readable)."}},"required":["deleted","id"],"type":"object"},"annotations":{"destructiveHint":true,"idempotentHint":false,"openWorldHint":false,"readOnlyHint":false},"access_tier":"gated","feature_keys":["projects_tasks"]},{"name":"roadmap_entry_link_project","title":"Link Project to Roadmap Entry","description":"Links a project to a roadmap entry so the entry can carry\nexecution context (which projects are actually delivering\nit).\n\nConstraints:\n- The project must belong to the same workspace as the roadmap.\n  Cross-workspace links are rejected with a validation error.\n- Idempotent: re-linking the same project returns the\n  existing link row without raising.\n\nWrites an `entry_project_linked` activity row. Reverse with\n`roadmap_entry_unlink_project`.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"roadmap_entry_id":{"type":"string","description":"Entry prefix ID (rent_…)."},"project_id":{"type":"string","description":"Project prefix ID (proj_…). Must belong to the same workspace as the roadmap."}},"required":["account_id","roadmap_entry_id","project_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"link":{"type":"object","properties":{"id":{"type":"string","description":"Link prefix ID (rep_…)."},"roadmap_entry_id":{"type":"string","description":"rent_…"},"project_id":{"type":"string","description":"proj_…"},"project_name":{"type":"string","description":"Denormalised for convenience — saves a separate `project_get`."}},"required":["id","roadmap_entry_id","project_id","project_name"]}},"required":["link"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":false},"access_tier":"gated","feature_keys":["projects_tasks"]},{"name":"roadmap_entry_move","title":"Move Roadmap Entry","description":"Moves a roadmap entry to a different roadmap **in the same\nworkspace**. The entry keeps its title, description, status, dates\nand every linked project — only its parent roadmap (and a\nfresh tail position) change. An `entry_moved` activity is\nwritten to BOTH roadmaps' feeds.\n\nSame-workspace only: an entry inherits its roadmap's workspace and its\nproject links are workspace-bound, so a cross-workspace target is\nrejected. Move the projects' workspace or unlink first if you need\nto reorganise across workspaces.\n\nTwo-step confirmation (the move is not silent): the first call\n— with `confirm` omitted or false — performs NO change and\nreturns a preview (`confirm_required: true`) describing the\nsource and target. Repeat the call with `confirm: true` to\nactually move the entry. Surface the preview to the user and\nget their go-ahead before confirming.\n\nAuth: the actor must be able to update both the entry's current\nroadmap and the target roadmap.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string","description":"Account prefix ID (acct_…)."},"id":{"type":"string","description":"Entry prefix ID (rent_…)."},"target_roadmap_id":{"type":"string","description":"Destination roadmap prefix ID (rmap_…). Must be in the same workspace as the entry."},"confirm":{"type":"boolean","description":"Must be true to execute. Omit/false returns a dry-run preview and changes nothing."}},"required":["account_id","id","target_roadmap_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"moved":{"type":"boolean","description":"True once the move has been executed; false on a preview."},"confirm_required":{"type":"boolean","description":"True on a preview — call again with confirm: true to execute."},"from":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"}},"required":["id","title"]},"to":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"}},"required":["id","title"]},"entry":{"type":"object","description":"The entry payload (current state on preview, post-move state on execute)."}},"required":["moved","from","to","entry"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":false,"openWorldHint":false,"readOnlyHint":false},"access_tier":"gated","feature_keys":["projects_tasks"]},{"name":"roadmap_entry_save","title":"Create or Update Roadmap Entry","description":"Linear-style upsert for one row inside a roadmap. Omit `id`\nto create, pass `id` to update.\n\nCreate requires `roadmap_id`, `title`, AND `due_on`. The\nentry inherits its workspace from the parent roadmap. This tool\ncan't reparent an entry — use `roadmap_entry_move` to move it\nto another roadmap in the same workspace.\n\nField semantics:\n- `status` ∈ {planned, in_progress, done, cancelled}. Defaults\n  to `planned` on create. Status changes write a\n  `RoadmapActivity` row visible via `roadmap_activities`.\n- Dates are ISO 8601 (`YYYY-MM-DD`). `due_on` must be on or\n  after `starts_on` when both are set.\n- `due_on` is mandatory and stays mandatory — there's no\n  open-ended state. If the work is genuinely ongoing, split\n  it into time-boxed chunks (e.g. one entry per quarter)\n  rather than picking a fake date.\n- `starts_on` may be null. An entry with no `starts_on`\n  renders as a milestone (diamond marker on the timeline)\n  at `due_on`.\n- `position` is a manual integer ordering inside the\n  roadmap; smaller = earlier. Defaults to 0 on create.\n- `owner_id` accepts an active human workspace member. It\n  defaults to the calling user on create.\n- Update semantics: fields you omit are left untouched.\n\nTo attach projects, use `roadmap_entry_link_project` — this\ntool only manages the entry's own fields.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"id":{"type":"string","description":"Entry prefix ID (rent_…). Omit to create."},"roadmap_id":{"type":"string","description":"Required on create. Roadmap prefix ID (rmap_…)."},"title":{"type":"string","description":"Required on create."},"description_markdown":{"type":["string","null"],"description":"Markdown. Empty string clears, null leaves alone."},"status":{"type":"string","enum":["planned","in_progress","done","cancelled"],"description":"Defaults to planned on create."},"starts_on":{"type":["string","null"],"description":"ISO date (YYYY-MM-DD). Null/omit → milestone-style entry."},"due_on":{"type":["string","null"],"description":"ISO date (YYYY-MM-DD). REQUIRED on create. Must be >= starts_on when set."},"position":{"type":"integer","description":"Manual ordering within the roadmap. Defaults to 0."},"owner_id":{"type":"string","description":"Owner user prefix ID or @handle. Defaults to the caller on create."}},"required":["account_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"entry":{"type":"object","properties":{"id":{"type":"string","description":"rent_…"},"title":{"type":"string"},"status":{"type":"string","enum":["planned","in_progress","done","cancelled"]},"starts_on":{"type":["string","null"]},"due_on":{"type":["string","null"]},"position":{"type":"integer"},"description_markdown":{"type":["string","null"]},"owner":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name"]},"projects":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"color":{"type":["string","null"]}},"required":["id","name"]}},"roadmap":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"}},"required":["id","title"]}},"required":["id","title","status","position","owner","projects","roadmap"]}},"required":["entry"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":false,"openWorldHint":false,"readOnlyHint":false},"access_tier":"gated","feature_keys":["projects_tasks"]},{"name":"roadmap_entry_unlink_project","title":"Unlink Project from Roadmap Entry","description":"Removes the link between a project and a roadmap entry. The\nunderlying project is not affected — only the association\nrow is dropped.\n\nIdempotent: unlinking an already-unlinked project returns\n`deleted: true` without error. Writes an\n`entry_project_unlinked` activity row when a real link was\nremoved.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"roadmap_entry_id":{"type":"string","description":"Entry prefix ID (rent_…)."},"project_id":{"type":"string","description":"Project prefix ID (proj_…)."}},"required":["account_id","roadmap_entry_id","project_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"deleted":{"type":"boolean","description":"Always true on success, regardless of whether a link actually existed."}},"required":["deleted"],"type":"object"},"annotations":{"destructiveHint":true,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":false},"access_tier":"gated","feature_keys":["projects_tasks"]},{"name":"roadmap_get","title":"Get Roadmap","description":"Fetches a single roadmap with full Markdown description,\nevery entry in display order, and each entry's linked\nprojects.\n\nUse this when you need to read or diff a roadmap's contents.\nPair with `roadmap_save` / `roadmap_entry_save` to write back —\ndescriptions round-trip via Markdown ↔ Tiptap without loss.\n\nErrors with `not found or not accessible` when the roadmap\ndoesn't exist OR the caller has no access (the message is\nambiguous on purpose to prevent ID enumeration).","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"id":{"type":"string","description":"Roadmap prefix ID (rmap_…)."}},"required":["account_id","id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"roadmap":{"type":"object","properties":{"id":{"type":"string","description":"rmap_…"},"title":{"type":"string"},"status":{"type":"string","enum":["planned","in_progress","done"]},"archived":{"type":"boolean"},"workspace":{"type":"object","properties":{"id":{"type":"string"},"key":{"type":"string"},"name":{"type":"string"}},"required":["id","key","name"]},"entry_count":{"type":"integer"},"updated_at":{"type":"string","description":"ISO 8601."},"created_at":{"type":"string","description":"ISO 8601."},"description_markdown":{"type":["string","null"]},"entries":{"type":"array","description":"All entries in display order (position asc, id asc).","items":{"type":"object","properties":{"id":{"type":"string","description":"rent_…"},"title":{"type":"string"},"status":{"type":"string","enum":["planned","in_progress","done","cancelled"]},"starts_on":{"type":["string","null"],"description":"ISO date (YYYY-MM-DD) or null."},"due_on":{"type":["string","null"],"description":"ISO date (YYYY-MM-DD)."},"position":{"type":"integer","description":"Manual ordering within the roadmap."},"description_markdown":{"type":["string","null"]},"owner":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name"]},"projects":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"proj_…"},"name":{"type":"string"},"color":{"type":["string","null"]}},"required":["id","name"]}}},"required":["id","title","status","position","owner","projects"]}}},"required":["id","title","status","archived","workspace","entries"]}},"required":["roadmap"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":true},"access_tier":"gated","feature_keys":["projects_tasks"]},{"name":"roadmap_list","title":"List Roadmaps","description":"Lists roadmaps the caller can read in the current account.\n\nVisibility: admins and employers see every roadmap in the\naccount. Other members see only roadmaps in workspaces they're a\nmember of.\n\nFilters:\n- `workspace_id` accepts the workspace's prefix ID (`wsp_…`) or its\n  short key (e.g. `ENG`).\n- `archived` defaults to false; set true to list archived\n  roadmaps instead of active ones.\n- `query` is a case-insensitive substring match on `title`.\n\nReturns rows ordered by `updated_at` desc, capped at 250.\nPass any row's `id` (rmap_…) to `roadmap_get` for the full\npayload including entries and linked projects.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"workspace_id":{"type":"string","description":"Workspace prefix ID (wsp_…) or short key (e.g. ENG)."},"archived":{"type":"boolean","description":"Default false. Set true to list archived roadmaps instead of active ones."},"query":{"type":"string","description":"Case-insensitive substring match on title."}},"required":["account_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"roadmaps":{"type":"array","description":"Up to 250 rows, sorted by updated_at desc.","items":{"type":"object","properties":{"id":{"type":"string","description":"Roadmap prefix ID (rmap_…)."},"title":{"type":"string"},"status":{"type":"string","enum":["planned","in_progress","done"],"description":"Editorial state of the roadmap."},"archived":{"type":"boolean"},"workspace":{"type":"object","properties":{"id":{"type":"string"},"key":{"type":"string"},"name":{"type":"string"}},"required":["id","key","name"]},"entry_count":{"type":"integer"},"updated_at":{"type":"string","description":"ISO 8601."},"created_at":{"type":"string","description":"ISO 8601."}},"required":["id","title","status","archived","workspace","entry_count","updated_at","created_at"]}}},"required":["roadmaps"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":true},"access_tier":"gated","feature_keys":["projects_tasks"]},{"name":"roadmap_save","title":"Create or Update Roadmap","description":"Linear-style upsert for a roadmap (the container, not its\nentries). Omit `id` to create, pass `id` to update.\n\nCreate requires `title` AND `workspace_id`. Workspace is immutable\nafter creation — `workspace_id` is silently ignored on update\n(entries are workspace-scoped, so switching workspaces would orphan\nthem).\n\nUpdate semantics:\n- Fields you omit are left untouched (no silent clears).\n- `archived: true` archives, `false` unarchives, omitted\n  leaves the state alone. Independent of `status`.\n- `status` is one of `planned` / `in_progress` / `done`.\n- Description accepts Markdown and round-trips via Tiptap\n  JSON. Passing an empty string clears the description.\n\nTo manage entries, use `roadmap_entry_save` /\n`roadmap_entry_destroy` — this tool doesn't touch them.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"id":{"type":"string","description":"Roadmap prefix ID (rmap_…). Omit to create."},"workspace_id":{"type":"string","description":"Required on create. Workspace prefix ID or short key (e.g. ENG). Ignored on update."},"title":{"type":"string","description":"Required on create."},"status":{"type":"string","enum":["planned","in_progress","done"],"description":"Editorial state. Defaults to planned on create; left alone on update when omitted."},"description_markdown":{"type":["string","null"],"description":"Markdown. Empty string clears the description; null leaves it alone."},"archived":{"type":"boolean","description":"true=archive, false=unarchive, omit=leave alone."}},"required":["account_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"roadmap":{"type":"object","properties":{"id":{"type":"string","description":"rmap_…"},"title":{"type":"string"},"status":{"type":"string","enum":["planned","in_progress","done"]},"archived":{"type":"boolean"},"workspace":{"type":"object","properties":{"id":{"type":"string"},"key":{"type":"string"},"name":{"type":"string"}},"required":["id","key","name"]},"entry_count":{"type":"integer"},"updated_at":{"type":"string","description":"ISO 8601."},"created_at":{"type":"string","description":"ISO 8601."}},"required":["id","title","status","archived","workspace","entry_count","updated_at","created_at"]}},"required":["roadmap"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":false,"openWorldHint":false,"readOnlyHint":false},"access_tier":"gated","feature_keys":["projects_tasks"]},{"name":"standup_list","title":"Get Standup Entries","description":"Reads daily standup entries (Yesterday / Today / Blockers).\nUnique per `(user, account, report_date)` — one per person per day.\n\nAdmin / employer see all members' entries (filter via `user_id`);\nregular members see only their own.\n\n- `blocked` is derived from `blockers.present?` when the flag\n  column is nil; when explicitly set, that value wins.\n- `submitted == completed_at.present?`. Drafts may be partial.\n- `previous_completed: false` on a submitted entry → carryover\n  signal (yesterday's plan didn't finish).\n- Sorted `report_date DESC, user_id ASC`, capped at 500 rows.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string","description":"Account prefix ID (e.g., acct_abc123)."},"user_id":{"type":"string","description":"User prefix ID (user_…) or @handle / handle (e.g., 'sam' or '@sam'). Admin/employer only for foreign users — regular members may pass their own or omit."},"start_date":{"type":"string","format":"date","description":"Inclusive lower bound on report_date (YYYY-MM-DD). Use alone for a single day."},"end_date":{"type":"string","format":"date","description":"Inclusive upper bound on report_date. Defaults to start_date when only start_date is given — pair them for a range."}},"required":["account_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"standup_entries":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Standup prefix ID (sup_…). Unique per (user, account, report_date)."},"user":{"type":"object","properties":{"id":{"type":["string","null"]},"handle":{"type":["string","null"]},"name":{"type":"string"}}},"report_date":{"type":"string","format":"date"},"previous":{"type":["string","null"],"description":"Yesterday's work / outcomes."},"next":{"type":["string","null"],"description":"Today's plan."},"blockers":{"type":["string","null"]},"blocked":{"type":"boolean","description":"Derived from blockers.present? when the flag column is nil; otherwise the stored value."},"previous_completed":{"type":["boolean","null"],"description":"User confirmed yesterday's plan finished."},"submitted":{"type":"boolean","description":"True iff completed_at is set — otherwise it's a draft."},"completed_at":{"type":["string","null"],"format":"date-time"}},"required":["id","user","report_date","blocked","submitted"]}}},"required":["standup_entries"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":true},"access_tier":"gated","feature_keys":["standups"]},{"name":"standup_save","title":"Create or Update Standup Entry","description":"Linear-style upsert for a daily standup entry (Yesterday /\nToday / Blockers). Omit `id` to upsert by `(user, account,\nreport_date)` — the same shape the web form uses. Pass `id`\n(sup_…) to update a specific entry.\n\n- `report_date` defaults to today. One entry per (user, date).\n- `submit: false` (the default) leaves the entry in draft\n  (completed_at IS NULL) so a human can review in the UI\n  before submitting. Set `submit: true` to submit immediately;\n  on an already-submitted entry, `submit: true` is a no-op\n  (completed_at is preserved).\n- At least one of `previous` / `next` / `blockers` must be\n  non-blank across create + update combined (matches the\n  model's `present_content` validation).\n- `previous_completed` is the \"yesterday's plan finished?\"\n  carryover flag surfaced by `standup_list`. Pass `true` /\n  `false` explicitly; omit to leave unchanged.\n\n## Body format\n\nBodies are stored as Markdown and rendered through the\nStandups account pipeline (ENG-1387). Write bullet lists;\nthe renderer decorates each line with a coloured status\npill when it ends with `result: <slug>`. Ticket keys like\n`ENG-1234` are autolinked automatically — do not wrap them\nin Markdown links yourself.\n\nRecognised status slugs (case-insensitive):\n`done` (also: ok, completed, shipped, landed),\n`in progress` (wip, ongoing, started, working),\n`in review` (review, reviewing, pr),\n`blocked` (blocker, waiting, stuck),\n`postponed` (on hold, paused, deferred, delayed, later),\n`cancelled` (canceled, dropped, abandoned, skipped).\nAnything else falls back to a neutral `planned` pill.\n\nExample `previous` body:\n\n    - Wrapped up ENG-1387 rendering pipeline, result: done\n    - Reviewed PR for ENG-1400, result: in review\n    - Waiting on staging deploy for ENG-1234, result: blocked\n\nPlain paragraphs and lists without `result: …` render fine\ntoo — they just skip the pill decoration.\n\n## Access (StandupEntryPolicy)\n\n- Regular members can only save their own entry — a `user_id`\n  for someone else is silently forced back to the caller.\n- Admin / employer can `user_id` to any active member.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"id":{"type":"string","description":"StandupEntry prefix ID (sup_…). Omit to upsert by (user, report_date)."},"user_id":{"type":"string","description":"User prefix (user_…) or @handle. Admin / employer only; regular members always save their own row."},"report_date":{"type":"string","format":"date","description":"YYYY-MM-DD. Defaults to today."},"previous":{"type":["string","null"],"description":"Yesterday's work / outcomes."},"next":{"type":["string","null"],"description":"Today's plan."},"blockers":{"type":["string","null"],"description":"Blockers. Non-blank flips derived `blocked` on."},"previous_completed":{"type":["boolean","null"],"description":"User confirmed yesterday's plan finished."},"submit":{"type":"boolean","description":"true = submit now; false (default) = leave as draft."}},"required":["account_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"id":{"type":"string"},"user":{"type":"object","properties":{"id":{"type":"string"},"handle":{"type":"string"},"name":{"type":"string"}}},"report_date":{"type":"string","format":"date"},"previous":{"type":["string","null"]},"next":{"type":["string","null"]},"blockers":{"type":["string","null"]},"blocked":{"type":"boolean"},"previous_completed":{"type":["boolean","null"]},"submitted":{"type":"boolean"},"completed_at":{"type":["string","null"],"format":"date-time"},"created":{"type":"boolean","description":"true iff this call inserted a fresh row (as opposed to updating an existing draft/submitted one)."}},"required":["id","user","report_date","blocked","submitted","created"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":false,"openWorldHint":false,"readOnlyHint":false},"access_tier":"gated","feature_keys":["standups"]},{"name":"task_comment_save","title":"Comment on a Task","description":"Posts a Markdown comment on a task; the body is converted to\nTiptap JSON for storage. Pair with `attachment_upload`\n+ `attachment_ids` to ship screenshots / logs alongside the\ncomment.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"task_id":{"type":"string","description":"Task prefix or KEY-N."},"body_markdown":{"type":"string"},"parent_id":{"type":"string","description":"Prefix ID (cmt_…) of the comment this is a reply to. One level only — replying to a reply re-roots at the original parent."},"attachment_ids":{"type":"array","items":{"type":"string"},"description":"Attachment handles from `attachment_upload` — att_… ids or file_urls. Files appear under the comment in the task UI."}},"required":["account_id","task_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"comment":{"type":"object","properties":{"id":{"type":"string"},"body_markdown":{"type":"string"}},"required":["id","body_markdown"]}},"required":["comment"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":false,"openWorldHint":false,"readOnlyHint":false},"access_tier":"gated","feature_keys":["projects_tasks"]},{"name":"task_get","title":"Get Task","description":"Fetches a single task by prefix id (`task_…`) or by issue\nkey in the form `{WORKSPACE_KEY}-{number}` (e.g. `ENG-3`,\n`VSUP-1000`). Returns the full description as Markdown plus\ncomments (chronological), parent/sub-issues, the Blocks /\nBlocked-by / Related / Duplicate relations, and — when\n`include_activity` is true — the activity timeline (status\nflips, assignee changes, comments, etc.) as humanised event\nrows. The payload's `url` field is the canonical web URL.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"id":{"type":"string","description":"Task prefix ID (task_…) or issue key (ENG-3)."},"include_comments":{"type":"boolean","default":true},"include_relations":{"type":"boolean","default":true},"include_activity":{"type":"boolean","default":false,"description":"Include `activity[]` — chronological event log (created / status_changed / assignee_changed / commented / …). Comments also appear here as `commented` rows alongside the dedicated `comments[]` array (ENG-1146)."}},"required":["account_id","id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"task":{"type":"object","properties":{"id":{"type":"string"},"key":{"type":"string"},"title":{"type":"string"}},"required":["id","key","title"]}},"required":["task"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":true},"access_tier":"gated","feature_keys":["projects_tasks","simple_projects_tasks"]},{"name":"task_list","title":"List Tasks","description":"Lists tasks (issues) the caller can read in the account.\nFilters: project, workspace, status (configured TaskStatus name or\nsymbolic key), priority, assignee, label, free-text search on\nthe title. Sorted by `updated_at DESC`, capped at 250 rows.\nEach row carries a canonical `url` field\n(`/tasks/{WORKSPACE_KEY}-{number}`) that an agent can paste back\nto humans without inventing a path.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"project_id":{"type":"string","description":"Project prefix ID or slug."},"workspace_id":{"type":"string","description":"Workspace prefix ID or key."},"cycle_id":{"type":"string","description":"Cycle prefix ID (cyc_…). Filters to tasks attached to that cycle."},"status":{"type":"string","description":"Task status name (e.g. 'In progress') or symbolic key (e.g. 'todo')."},"priority":{"type":"string","description":"Priority enum key (urgent / high / medium / low / no_priority)."},"assignee":{"type":"string","description":"User prefix ID or @handle. 'me' resolves to the caller; 'none' filters unassigned."},"label":{"type":"string","description":"Label name or prefix ID."},"subscribed":{"type":"boolean","description":"Only tasks you are subscribed to."},"series_id":{"type":"string","description":"Recurring task series prefix ID (trs_…). Filters generated parent tasks."},"query":{"type":"string","description":"Substring match on title."},"limit":{"type":"integer","default":50,"description":"Max rows (default 50, max 250)."}},"required":["account_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"tasks":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"key":{"type":"string"},"title":{"type":"string"}},"required":["id","key","title"]}}},"required":["tasks"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":true},"access_tier":"gated","feature_keys":["projects_tasks","simple_projects_tasks"]},{"name":"task_move_to_workspace","title":"Move Task To Workspace","description":"Moves a task to a different workspace. The task keeps its\ncomments, attachments, history, assignee, due date,\nestimate and priority — but gets a fresh issue key on the\ntarget workspace (e.g. ENG-12 → DEV-5). Labels are stripped\n(labels are workspace-bound); the project is cleared unless you\npass `project_id` of a project that belongs to the target\nworkspace. Status is remapped to the equivalent column in the\ntarget workspace when one exists (by `symbolic_key`).\n\nAuth: moving an issue changes its identifier and outer access\nboundary, so only account admins can perform this operation.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string","description":"Account prefix ID (acct_…)."},"task_id":{"type":"string","description":"Task prefix ID (task_…) or issue key (ENG-12)."},"workspace_id":{"type":"string","description":"Target workspace — prefix ID (wsp_…) or short key (e.g. DEV). Legacy team_ links remain accepted during migration."},"project_id":{"type":"string","description":"Optional project prefix ID (proj_…). Must belong to the target workspace. Pass empty / omit to leave the task project-less after the move."}},"required":["account_id","task_id","workspace_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"task":{"type":"object","properties":{"id":{"type":"string"},"key":{"type":"string"},"title":{"type":"string"},"previous_key":{"type":"string"},"cleared":{"type":"array","items":{"type":"string"}}},"required":["id","key","title","previous_key","cleared"]}},"required":["task"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":false,"openWorldHint":false,"readOnlyHint":false},"access_tier":"gated","feature_keys":["projects_tasks"]},{"name":"task_relation_save","title":"Set Task Relation","description":"Add or remove a task relation within the same account. source_task watches target_task resumes the agent's source task when the target changes. Task delegation creates this relation automatically.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"source_task_id":{"type":"string"},"target_task_id":{"type":"string"},"kind":{"type":"string","enum":["blocks","related_to","duplicate_of","watches"]},"active":{"type":"boolean","default":true}},"required":["account_id","source_task_id","target_task_id","kind"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"relation":{"type":"object","properties":{"id":{"type":["string","null"]},"source_task_id":{"type":"string"},"target_task_id":{"type":"string"},"kind":{"type":"string"},"active":{"type":"boolean"}},"required":["id","source_task_id","target_task_id","kind","active"]}},"required":["relation"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":false},"access_tier":"gated","feature_keys":["projects_tasks","simple_projects_tasks"]},{"name":"task_save","title":"Create or Update Task","description":"Linear-style upsert. Pass `id` (prefix or `KEY-N`) to update,\nomit it to create. On create the workspace is required (omit when\nupdating). Description accepts Markdown and is converted to\nTiptap JSON for storage; readers get Markdown back via\n`task_get` so the round-trip is symmetric.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"idempotency_key":{"type":"string","description":"Stable unique key for this intended task. Reuse on retries. Required when delegating from a task session; creates a subscription that resumes your coordinating task."},"id":{"type":"string","description":"Task prefix ID or KEY-N. Omit to create."},"workspace_id":{"type":"string","description":"Workspace prefix ID or key. Required on create."},"project_id":{"type":["string","null"],"description":"Project prefix ID (proj_…) or slug. Pass null to detach the task from its project."},"cycle_id":{"type":["string","null"],"description":"Cycle prefix ID (cyc_…). Cycle must belong to the same workspace as the task; pass null to detach."},"pinned_to_cycle":{"type":"boolean","description":"ENG-1094. When true, the task stays on its current cycle when that cycle closes (excluded from carry-over)."},"parent_task_id":{"type":["string","null"],"description":"Parent task prefix ID (task_…) or KEY-N. Pass null to make this a top-level task."},"title":{"type":"string"},"description_markdown":{"type":["string","null"]},"status":{"type":"string","description":"TaskStatus name or symbolic key."},"priority":{"type":"string"},"assignee":{"type":["string","null"],"description":"User prefix or @handle. 'none' clears."},"start_on":{"type":["string","null"],"description":"ISO date YYYY-MM-DD or null to clear. Optional, must be on or before due_on when both are set."},"due_on":{"type":["string","null"],"description":"ISO date YYYY-MM-DD or null to clear."},"start_at":{"type":["string","null"],"description":"ISO 8601 timestamp with UTC offset. Sets start_on in time_zone. Null removes only the time. Automatic agent work waits until this instant."},"due_at":{"type":["string","null"],"description":"ISO 8601 timestamp with UTC offset. Sets due_on in time_zone. Null removes only the time."},"time_zone":{"type":"string","description":"Task time zone, e.g. Europe/Berlin. Defaults to the creator's time zone."},"estimate_points":{"type":["integer","null"]},"labels":{"type":"array","items":{"type":"string"},"description":"List of label names or prefix IDs."},"attachment_ids":{"type":"array","items":{"type":"string"},"description":"Attachment handles from `attachment_upload` — att_… ids or file_urls. Files appear in the task's attachments list. Existing attachments are kept; pass an empty array to add nothing new (use the web UI to remove)."}},"required":["account_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"task":{"type":"object","properties":{"id":{"type":"string"},"key":{"type":"string"},"title":{"type":"string"}},"required":["id","key","title"]}},"required":["task"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":false,"openWorldHint":false,"readOnlyHint":false},"access_tier":"gated","feature_keys":["projects_tasks"]},{"name":"task_series_delete","title":"Delete Recurring Task Series","description":"Delete a recurring series and stop future generation. All already created tasks and subtasks are kept. Requires creator, workspace manager or account admin and expected_version from task_series_get.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"id":{"type":"string"},"expected_version":{"type":"integer"}},"required":["account_id","id","expected_version"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"deleted":{"type":"boolean"},"id":{"type":"string"},"existing_tasks_kept":{"type":"boolean"}},"required":["deleted","id","existing_tasks_kept"],"type":"object"},"annotations":{"destructiveHint":true,"idempotentHint":false,"openWorldHint":false,"readOnlyHint":false},"access_tier":"gated","feature_keys":["projects_tasks"]},{"name":"task_series_get","title":"Get Recurring Task Series","description":"Read a recurring task template, schedule, version and occurrence history. Tasks are independent copies. The cursor uses planned due dates and is not changed by editing or completing a task.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"id":{"type":"string","description":"Series prefix ID (trs_…)."},"before":{"type":"string","description":"Occurrence prefix ID for older history."},"limit":{"type":"integer","minimum":1,"maximum":100}},"required":["account_id","id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"series":{"type":"object"},"occurrences":{"type":"array","items":{"type":"object"}},"next_cursor":{"type":["string","null"]}},"required":["series","occurrences","next_cursor"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":true},"access_tier":"gated","feature_keys":["projects_tasks","simple_projects_tasks"]},{"name":"task_series_list","title":"List Recurring Task Series","description":"List accessible recurring task series, including paused and blocked schedules. Use task_series_get for the template and generated task history.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"workspace_id":{"type":"string","description":"Workspace prefix ID or key."},"paused":{"type":"boolean"},"after":{"type":"string","description":"Series prefix ID for the next page."},"limit":{"type":"integer","minimum":1,"maximum":100}},"required":["account_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"series":{"type":"array","items":{"type":"object"}},"next_cursor":{"type":["string","null"]}},"required":["series","next_cursor"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":true},"access_tier":"gated","feature_keys":["projects_tasks","simple_projects_tasks"]},{"name":"task_series_save","title":"Save Recurring Task Series","description":"Create or update a recurring task series. Creation immediately makes one task at the first scheduled due date on or after today.\nLater tasks are created at 00:01 in the series time zone the day after the previous PLANNED due date, regardless of completion.\ndays/weeks/months/years, interval 1–12; month ends clamp. Missed historical dates are skipped.\nCreate requires workspace_id, frequency, anchor_on and time_zone, plus template.title or source_task_id.\nsource_task_id copies the task and its subtasks into a NEW series and NEW tasks; the source stays unchanged.\nUpdate requires id and expected_version from task_series_get. Omitted fields are preserved; template patches root fields, children replaces the entire child tree.\nChanging anchor_on creates an ADDITIONAL task immediately and resets the schedule. Content/interval edits preserve existing tasks and cursor.\npaused stops generation; resuming skips missed history. auto_start_agents defaults false: assigned agents wait for a status/assignment change.\nEvery save makes the caller responsible for future generation; revoked workspace/feature access blocks it.\nUse a stable idempotency_key when creating to make retries safe. Do not use task_save to edit a series.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"id":{"type":"string"},"expected_version":{"type":"integer"},"workspace_id":{"type":"string"},"source_task_id":{"type":"string"},"idempotency_key":{"type":"string","maxLength":200},"frequency":{"type":"string","enum":["days","weeks","months","years"]},"interval":{"type":"integer","minimum":1,"maximum":12},"anchor_on":{"type":"string","description":"ISO date YYYY-MM-DD. Changing this restarts the schedule and creates another task."},"time_zone":{"type":"string","description":"IANA zone, e.g. Europe/Berlin."},"paused":{"type":"boolean"},"auto_start_agents":{"type":"boolean"},"start_time":{"type":["string","null"],"description":"Optional local HH:MM start time on each planned date, e.g. 08:00 or 20:00. Automatic agent work waits until this time."},"due_time":{"type":["string","null"],"description":"Optional local HH:MM deadline on each planned date. Null removes the time. Must not be before start_time."},"template":{"type":"object","properties":{"title":{"type":"string","maxLength":200},"description_markdown":{"type":"string","maxLength":100000},"priority":{"type":"string","enum":["no_priority","urgent","high","medium","low"]},"status_id":{"type":"string","description":"Workspace task status prefix ID (tst_…)."},"assignee_id":{"type":["string","null"],"description":"User prefix ID (user_…), null to clear."},"project_id":{"type":["string","null"],"description":"Project prefix ID (proj_…), null to clear."},"estimate_points":{"type":["integer","null"],"minimum":0,"maximum":999},"label_ids":{"type":"array","items":{"type":"string"},"maxItems":50},"children":{"type":"array","maxItems":50,"items":{"type":"object","description":"Child template with the same fields; nested children up to 5 levels, 50 total.","properties":{"title":{"type":"string","maxLength":200},"description_markdown":{"type":"string","maxLength":100000},"priority":{"type":"string","enum":["no_priority","urgent","high","medium","low"]},"status_id":{"type":"string","description":"Workspace task status prefix ID (tst_…)."},"assignee_id":{"type":["string","null"],"description":"User prefix ID (user_…), null to clear."},"project_id":{"type":["string","null"],"description":"Project prefix ID (proj_…), null to clear."},"estimate_points":{"type":["integer","null"],"minimum":0,"maximum":999},"label_ids":{"type":"array","items":{"type":"string"},"maxItems":50},"children":{"type":"array","items":{"type":"object"}}}}}},"additionalProperties":false}},"required":["account_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"series":{"type":"object"}},"required":["series"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":false,"openWorldHint":false,"readOnlyHint":false},"access_tier":"gated","feature_keys":["projects_tasks"]},{"name":"task_wait","title":"Wait for Watched Tasks","description":"Yield your current task turn while waiting for subscribed tasks. No polling or empty progress comment is needed. Finish your response after calling; relevant changes resume this same task session automatically. Does not complete the task.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"}},"required":["account_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"waiting":{"type":"boolean"},"pending_tasks":{"type":"array","items":{"type":"object"}},"task_id":{"type":"string"}},"required":["waiting","pending_tasks","task_id"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":false},"access_tier":"gated","feature_keys":["projects_tasks","simple_projects_tasks"]},{"name":"task_watch","title":"Subscribe to Task","description":"Subscribe or unsubscribe yourself to task changes and Inbox notifications. Use task_relation_save with kind=watches for task-to-task coordination. Subscribing grants no additional access.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string"},"task_id":{"type":"string"},"active":{"type":"boolean","default":true}},"required":["account_id","task_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"subscription":{"type":"object","properties":{"id":{"type":"string"},"active":{"type":"boolean"},"task_id":{"type":"string"}},"required":["id","active","task_id"]}},"required":["subscription"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":false},"access_tier":"gated","feature_keys":["projects_tasks","simple_projects_tasks"]},{"name":"timeclock_list","title":"Get Time Clocks","description":"Reads TimeClock entries (check-in / check-out records). One row\nper work/pause session, or a full sick/vacation day.\n\nAdmin / employer see every member's entries (and may filter by\n`user_id`); regular members see only their own and can't pass a\nforeign `user_id`.\n\n- `checkin_out` is the real field name (not `checkout_at`).\n- `duration_seconds` is null on open entries (`is_open: true`)\n  so sums stay safely additive without filtering.\n- `created_on` is a local-time date — may differ from\n  `checkin_at.to_date` for late-night sessions.\n- Full-day sick/vacation still use 00:00–23:59 pair, `category: \"work\"`.\n- `comment == \"auto closed\"` flags nightly auto-close sweeps.\n- Sorted `checkin_at DESC`, capped at 500 rows.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string","description":"Account prefix ID (e.g., acct_abc123)."},"user_id":{"type":"string","description":"User prefix ID (user_…) or @handle / handle (e.g., 'sam' or '@sam'). Admin/employer only for foreign users."},"start_date":{"type":"string","format":"date","description":"Inclusive lower bound on created_on (YYYY-MM-DD). Use alone for a single day."},"end_date":{"type":"string","format":"date","description":"Inclusive upper bound on created_on. Defaults to start_date when only start_date is given — pair them for a range."}},"required":["account_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"time_clocks":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"TimeClock prefix ID (clk_…)."},"user":{"type":"object","properties":{"id":{"type":["string","null"]},"handle":{"type":["string","null"]},"name":{"type":"string"}}},"created_on":{"type":"string","format":"date","description":"Calendar day the entry belongs to (local-time assigned at check-in; may differ from checkin_at.to_date for late-night sessions)."},"checkin_at":{"type":["string","null"],"format":"date-time"},"checkin_out":{"type":["string","null"],"format":"date-time","description":"Null when entry is still open. Field name is intentional — not a typo for checkout_at."},"is_open":{"type":"boolean","description":"True iff checkin_out is null."},"category":{"type":"string","enum":["work","pause"]},"work_location_type":{"type":["string","null"],"enum":[null,"remote","on_site"]},"sick_day":{"type":"boolean"},"vacation_day":{"type":"boolean"},"comment":{"type":["string","null"],"description":"AUTO_CHECKOUT_COMMENT='auto closed' marks entries closed by the nightly sweep."},"duration_seconds":{"type":["integer","null"],"description":"Null on open entries to keep sums safely additive."}},"required":["id","user","created_on","is_open","category","sick_day","vacation_day"]}}},"required":["time_clocks"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":true},"access_tier":"gated","feature_keys":["timeclock"]},{"name":"whoami","title":"Who am I","description":"Returns your own identity and the account you act in. Call this\nFIRST in a session: every account-scoped tool requires an\n`account_id`, and this is where you get it — never invent or guess\none.\n\nWhen you belong to exactly one account, `account_id` is that\naccount and you can pass it to every other tool as-is. When you\nbelong to several, `account_id` is null and you must choose from\n`accounts` (a channel or task you were asked about belongs to\nexactly one of them).\n\nNo parameters. Read-only; safe to call at any time.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{},"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"current_user":{"type":"object","properties":{"id":{"type":"string","description":"User prefix ID (user_…)."},"handle":{"type":"string"},"name":{"type":"string"},"is_agent":{"type":"boolean","description":"True when you are a bot identity."},"db_id":{"type":"integer","description":"Integer PK — matches user.db_id in chat / time-clock / standup rows."}},"required":["id","handle","name","is_agent","db_id"]},"account_id":{"type":["string","null"],"description":"The account to pass as account_id — set when you belong to exactly one, null when you must choose."},"accounts":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Account prefix ID (acct_…)."},"name":{"type":"string"},"personal":{"type":"boolean"},"roles":{"type":"array","items":{"type":"string","enum":["admin","employer"]},"description":"Empty array = regular member."}},"required":["id","name","personal","roles"]}}},"required":["current_user","account_id","accounts"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":true},"access_tier":"basic","feature_keys":["none"]},{"name":"workspace_list","title":"List Workspaces","description":"Lists visible active workspaces in navigation order. Each\nworkspace carries the short `key` prefix used to compose issue keys\n(`{key}-{number}`, e.g. `ENG-128`) and the membership role of\nthe calling user. Pass include_archived: true to include archived\nworkspaces. Admins and employers can pass management: true to list\nall workspaces they can administer, including those they haven't joined.\nAgent workspace grants still apply. Use workspace_save to create,\nedit, archive or restore workspaces.\n\nENG-1089 — each row also carries the workspace's `cycles` config\nblock (enabled flag, duration in weeks or custom days,\ncooldown, start day, auto-create count, estimates_required).\nUseful when an agent needs to know how the workspace is set up\nbefore it talks about sprint windows or velocity.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string","description":"Account prefix ID (acct_…)."},"include_archived":{"type":"boolean","default":false},"management":{"type":"boolean","default":false,"description":"Admin/employer only: include workspaces you can administer without being a member."}},"required":["account_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"workspaces":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"key":{"type":"string"},"color":{"type":"string"},"description":{"type":["string","null"]},"icon_emoji":{"type":["string","null"]},"archived":{"type":"boolean"},"general":{"type":"boolean"},"key_editable":{"type":"boolean"},"tasks_enabled":{"type":"boolean"},"subtasks_enabled":{"type":"boolean"},"recurring_tasks_enabled":{"type":"boolean"},"projects_enabled":{"type":"boolean"},"roadmaps_enabled":{"type":"boolean"},"estimates_enabled":{"type":"boolean"},"estimate_scale":{"type":"string"},"role":{"type":["string","null"],"description":"manager / member / null when caller is not on the workspace."},"cycles":{"type":"object","description":"Per-workspace cycles config (ENG-1089). Most workspaces keep defaults; only meaningful once `enabled` is true.","properties":{"enabled":{"type":"boolean"},"duration_weeks":{"type":["integer","null"],"description":"1-4 weeks, or null when running on custom_days."},"custom_days":{"type":["integer","null"],"description":"Cycle length in days when duration_weeks is null."},"duration_days":{"type":["integer","null"],"description":"Collapsed day count — duration_weeks * 7 or custom_days, whichever is set."},"cooldown_weeks":{"type":"integer","description":"Gap between consecutive cycles, in weeks."},"start_day":{"type":"integer","description":"Date#wday-style: 0 = Sunday, 1 = Monday, …, 6 = Saturday."},"auto_create_count":{"type":"integer","description":"How many upcoming cycles the lifecycle scheduler keeps ahead."},"estimates_required":{"type":"boolean","description":"When true, tasks must carry an estimate before they can be added to a cycle (gates velocity metrics)."},"carry_over_mode":{"type":"string"},"carry_over_statuses":{"type":"array","items":{"type":"string"}}},"required":["enabled","cooldown_weeks","start_day","auto_create_count","estimates_required"]}},"required":["id","name","key","color","cycles","archived","general","key_editable"]}}},"required":["workspaces"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":true},"access_tier":"gated","feature_keys":["none"]},{"name":"workspace_save","title":"Create, Update or Archive Workspace","description":"Admins and employers can manage workspaces in their account. Omit id\nto create (name and key required); pass a wsp_… ID to update only the\nsupplied fields. The creator becomes a workspace manager. Keys are\nnormalized to uppercase and cannot change once the workspace has tasks.\nSet archived: true to archive or false to restore an existing workspace.\nArchiving preserves its contents; General cannot be archived.\nUse workspace_list(management: true, include_archived: true) to read\nsettings and discover all workspaces you can administer.\nWorkspace-scoped agents can only update already granted workspaces;\na workspace tool grant cannot authorize creating a new workspace.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"account_id":{"type":"string","description":"Account prefix ID (acct_…)."},"id":{"type":"string","description":"Workspace prefix ID (wsp_…). Omit to create."},"archived":{"type":"boolean","description":"Existing workspaces only: true archives, false restores."},"name":{"type":"string","description":"Required on create; at most 80 characters."},"key":{"type":"string","description":"Required on create; 2–4 letters/digits. Editable only before any tasks exist."},"color":{"type":"string","enum":["emerald","violet","amber","rose","sky","indigo","slate","gray"]},"description":{"type":["string","null"],"description":"Plain text. Null or an empty string clears it."},"icon_emoji":{"type":["string","null"],"description":"Unicode emoji. Null or an empty string clears it."},"tasks_enabled":{"type":"boolean"},"subtasks_enabled":{"type":"boolean"},"recurring_tasks_enabled":{"type":"boolean"},"projects_enabled":{"type":"boolean","description":"Requires tasks_enabled."},"roadmaps_enabled":{"type":"boolean","description":"Requires projects_enabled."},"estimates_enabled":{"type":"boolean"},"estimate_scale":{"type":"string","enum":["fibonacci","linear","powers_of_two"]},"cycles_enabled":{"type":"boolean","description":"Disabling archives upcoming cycles; active cycles remain."},"cycle_duration_weeks":{"type":["integer","null"],"description":"1–4 weeks; null selects cycle_custom_days."},"cycle_custom_days":{"type":["integer","null"],"description":"1–365 days when cycle_duration_weeks is null."},"cooldown_duration_weeks":{"type":"integer"},"cycle_start_day":{"type":"integer","description":"0 = Sunday through 6 = Saturday."},"auto_create_count":{"type":"integer"},"carry_over_mode":{"type":"string","enum":["off","all","by_status"]},"carry_over_statuses":{"type":"array","items":{"type":"string"},"description":"Task status symbolic keys; only valid with carry_over_mode: by_status."}},"required":["account_id"],"type":"object"},"outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"workspace":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"key":{"type":"string"},"color":{"type":"string"},"description":{"type":["string","null"]},"icon_emoji":{"type":["string","null"]},"archived":{"type":"boolean"},"general":{"type":"boolean"},"key_editable":{"type":"boolean"},"tasks_enabled":{"type":"boolean"},"subtasks_enabled":{"type":"boolean"},"recurring_tasks_enabled":{"type":"boolean"},"projects_enabled":{"type":"boolean"},"roadmaps_enabled":{"type":"boolean"},"estimates_enabled":{"type":"boolean"},"estimate_scale":{"type":"string"},"role":{"type":["string","null"],"description":"manager / member / null when caller is not on the workspace."},"cycles":{"type":"object","description":"Per-workspace cycles config (ENG-1089). Most workspaces keep defaults; only meaningful once `enabled` is true.","properties":{"enabled":{"type":"boolean"},"duration_weeks":{"type":["integer","null"],"description":"1-4 weeks, or null when running on custom_days."},"custom_days":{"type":["integer","null"],"description":"Cycle length in days when duration_weeks is null."},"duration_days":{"type":["integer","null"],"description":"Collapsed day count — duration_weeks * 7 or custom_days, whichever is set."},"cooldown_weeks":{"type":"integer","description":"Gap between consecutive cycles, in weeks."},"start_day":{"type":"integer","description":"Date#wday-style: 0 = Sunday, 1 = Monday, …, 6 = Saturday."},"auto_create_count":{"type":"integer","description":"How many upcoming cycles the lifecycle scheduler keeps ahead."},"estimates_required":{"type":"boolean","description":"When true, tasks must carry an estimate before they can be added to a cycle (gates velocity metrics)."},"carry_over_mode":{"type":"string"},"carry_over_statuses":{"type":"array","items":{"type":"string"}}},"required":["enabled","cooldown_weeks","start_day","auto_create_count","estimates_required"]}},"required":["id","name","key","color","cycles","archived","general","key_editable"]}},"required":["workspace"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":false,"openWorldHint":false,"readOnlyHint":false},"access_tier":"gated","feature_keys":["none"]}]}