# Tools

Every tool the Koma MCP server offers, as a client sees it over `tools/list`. 21 tools, in 7 groups. Each one acts as the signed-in person, on their own workspace only, and returns both a text and a structured result.

This page is generated from the server's live registration. What you read here is what your client's model reads.

## At a glance

- **Context**: [`get_context`](#get_context)
- **Lists**: [`list_lists`](#list_lists), [`create_list`](#create_list), [`update_list`](#update_list), [`delete_list`](#delete_list)
- **Items**: [`list_items`](#list_items), [`get_item`](#get_item), [`query_items`](#query_items), [`create_items`](#create_items), [`update_items`](#update_items), [`move_items`](#move_items), [`delete_items`](#delete_items), [`create_image_upload`](#create_image_upload)
- **Search**: [`search`](#search)
- **Chats**: [`read_chat_messages`](#read_chat_messages), [`post_chat_message`](#post_chat_message)
- **Trash**: [`list_deleted`](#list_deleted), [`restore_deleted`](#restore_deleted)
- **Automations**: [`list_automations`](#list_automations), [`get_automation_runs`](#get_automation_runs), [`run_automation`](#run_automation)

**Reading the badges.** `Read-only` tools change nothing and a client can run them without asking. `Adds data` tools create something new and never touch what exists. `Updates or removes existing data` tools update or delete, and clients ask before each call by default. `Safe to retry` marks a call that lands once however often it is repeated. `Reaches outside Koma` marks a tool that touches something beyond the workspace: `run_automation` can act through the person's connected apps, and `create_items` and `update_items` download images from public URLs you name.

**Ids.** Every list, item and automation has a UUID. Tools that take an id answer "not found" for an id that belongs to someone else. Get ids from `get_context`, the list tools or `search`; never guess one.

**Time.** Instants are ISO 8601 with a zone. A window such as `createdAfter` and `createdBefore` includes its lower bound and excludes its upper bound. The person's timezone and today's date come from `get_context`.

**Errors.** A failed call returns `isError: true` with one sentence that says what to change. Nothing is thrown.

## Context

One call that orients a conversation: who the user is, their lists, what is due, recent notes, automations and what they asked Koma to remember.

### get_context

**Get workspace context** · `Read-only`

Use this at the start of a conversation that involves the user's Koma workspace, or when you need an overview of it. Returns, in one call: how Koma works; the user (name, timezone, today's date and local time); what they asked the AI to remember about them; their lists with ids, properties and item counts (the Tasks list and the Notes list named by id); overdue, due-today, in-progress and upcoming tasks; the newest unsorted tasks; recently touched notes; their automations with the last run; and the last few days of activity. Everything comes with ids for follow-up calls. It is an overview, not the full data: use search, list_items, query_items or get_item for depth. Pass focusListId to scope the task sections to one list.

**Parameters**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `focusListId` | `string` | no | Optional list id. Scopes the task sections to that list; the rest stays workspace-wide. |

**Returns**

- `about` (`string[]`)
- `user` (`object`)
- `unavailable` (`string[]`)
- `links` (`object`): The roots of a row's links: `<webOrigin>/artifacts/<id>` is the item's page in Koma, `<appScheme>://artifacts/<id>` the same item in the Koma Mac app.

**Example**

```json
{
  "method": "tools/call",
  "params": {
    "name": "get_context",
    "arguments": {}
  }
}
```

## Lists

The containers. Every list has a name, instructions and properties; the Tasks list and every list made for tasks keep a status and a due date on their items. Read the directory, create a list, change its shape, delete it.

### list_lists

**List lists** · `Read-only`

The user's lists: every live list with its id, name, icon, standing instructions, item count, layout and PROPERTIES with their stable ids — the ids create_items and update_items key values on. A list whose statusPropertyId is "status" and dueDatePropertyId is "dueDate" keeps a status and a due date on its items, which makes them tasks; the Tasks list and the Notes list are named by id. Use it to resolve a list's name to its id before writing to it, or to read a list's properties you have not seen yet. Pass suppressOptions: true when you only need names and counts; a select property can carry hundreds of options (a select value may be sent as its label).

**Parameters**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `suppressOptions` | `boolean` | no | true replaces each select property's option list with an optionCount — much smaller payload. |

**Returns**

- `total` (`number`)
- `tasksListId` (`string | null`)
- `notesListId` (`string | null`)
- `lists` (`object[]`)

**Example**

```json
{
  "method": "tools/call",
  "params": {
    "name": "list_lists",
    "arguments": {}
  }
}
```

### create_list

**Create list** · `Adds data`

Create a list. template "tasks" creates a list for to-dos: its items keep a status (todo / inProgress / completed) and a due date, like the Tasks list. Otherwise `properties` shape it (a reading list with Author and Status, a CRM with Company and Email); omit both to start with no properties — every item has a title. Check list_lists or get_context first so an existing list is not duplicated. Returns the list with its id and its properties' stable ids, ready for create_items.

**Parameters**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `name` | `string` | yes | The list's name, in the user's own words. |
| `icon` | `string \| null` | no | An emoji for the list. |
| `instructions` | `string \| null` | no | Standing rules for how entries should be handled, one rule per line. Max 500 characters — they ride in the prompt on every turn. |
| `template` | `"tasks" \| null` | no | "tasks" creates a list for to-dos that keeps a status and a due date. Omit for a list shaped by `properties`. |
| `properties` | `object[] \| null` | no | The list's own properties (3 to 6 is typical; a title exists on every item, so no title property). Ignored with template "tasks". |
| `titleLabel` | `string \| null` | no | What the title column is headed on this list — the word every item's name sits under: Name on a CRM, Book on a reading list. Omit for Title. Never a property: every item has a title. |

**Returns**

- `id` (`string`)
- `name` (`string`)
- `icon` (`string | null`)
- `instructions` (`string | null`)
- `titleLabel` (`string | null`): The title column's name on this list (Name on a CRM, Book on a reading list); null reads as Title. An item's name is its title under any label.
- `layout` (`string`)
- `role` (`"tasks" | "notes" | "other"`): What the list's items are, read from its properties: "tasks" when it keeps the status and the due date, "notes" when it has no properties, "other" when its properties are its own.
- `properties` (`object[]`)
- `statusPropertyId` (`string | null`): "status" when the list keeps its items' status in the task columns.
- `dueDatePropertyId` (`string | null`): "dueDate" when the list keeps its items' due date in the task columns.
- `itemCount` (`number`): The list's open items: every live item but a repeating template, and never a completed one on a list that keeps its status in the task columns.
- `isLifeAdmin` (`boolean`)

**Example**

```json
{
  "method": "tools/call",
  "params": {
    "name": "create_list",
    "arguments": {
      "name": "<name>"
    }
  }
}
```

### update_list

**Update list** · `Updates or removes existing data` · `Safe to retry`

Change a list: its name, icon, standing instructions, layout, or its properties. `instructions` REPLACES the existing text (read it first with list_lists and carry forward what is still true; null clears it). `addProperties` adds properties (every one in this call), `updateProperty` renames, retypes or re-options ONE property, `deletePropertyIds` removes properties, `columnOrder` reorders them. A retype migrates the items' values; one that would clear or trim values answers a PREVIEW (preview: true, what would be lost) and writes nothing until the same call is repeated with acknowledgeDataLoss: true. The reserved status and due date properties can be renamed, never retyped or removed. The title column is renamed through `titleLabel` (it stays every item's title), never retyped, removed or hidden. Only the fields passed change.

**Parameters**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `listId` | `string` | yes | The list's id (from list_lists or get_context). |
| `name` | `string \| null` | no | New name. Omit, or pass null, to leave it unchanged. |
| `icon` | `string \| null` | no | New emoji; "" removes it. Omit, or pass null, to leave it unchanged. |
| `instructions` | `string \| null` | no | REPLACES the standing rules (max 500 characters); "" clears them. Omit, or pass null, to leave them unchanged. |
| `titleLabel` | `string \| null` | no | The title column's new name on this list (Name, Book, Client); "" resets it to Title. Omit, or pass null, to leave it unchanged. The column stays every item's title under any name. |
| `layout` | `"list" \| "kanban" \| "table" \| null` | no | How the list opens: 'list', 'kanban' (the board) or 'table'. |
| `columnOrder` | `string[] \| null` | no | Left-to-right property order: EVERY property exactly once, by property id. |
| `addProperties` | `object[] \| null` | no | Properties to ADD, every one in this call. Existing items leave a new property unset. |
| `updateProperty` | `object \| null` | no | ONE property to rename, retype or re-option. |
| `deletePropertyIds` | `string[] \| null` | no | Stable ids of the properties to remove, every one in this call. |
| `acknowledgeDataLoss` | `boolean \| null` | no | true ONLY on a repeat call, after a preview reported items that would clear or trim and you told the user what will be lost. |

**Returns**

- `id` (`string`)
- `name` (`string`)
- `icon` (`string | null`)
- `instructions` (`string | null`)
- `titleLabel` (`string | null`): The title column's name on this list (Name on a CRM, Book on a reading list); null reads as Title. An item's name is its title under any label.
- `layout` (`string`)
- `role` (`"tasks" | "notes" | "other"`): What the list's items are, read from its properties: "tasks" when it keeps the status and the due date, "notes" when it has no properties, "other" when its properties are its own.
- `properties` (`object[]`)
- `statusPropertyId` (`string | null`): "status" when the list keeps its items' status in the task columns.
- `dueDatePropertyId` (`string | null`): "dueDate" when the list keeps its items' due date in the task columns.
- `itemCount` (`number`): The list's open items: every live item but a repeating template, and never a completed one on a list that keeps its status in the task columns.
- `isLifeAdmin` (`boolean`)
- `preview` (`boolean`)
- `warning` (`string`)

**Example**

```json
{
  "method": "tools/call",
  "params": {
    "name": "update_list",
    "arguments": {
      "listId": "<listId>"
    }
  }
}
```

### delete_list

**Delete list** · `Updates or removes existing data` · `Safe to retry`

Delete a list by id. Deleting the list also deletes EVERY item on it. SOFT delete: the list and its items are recoverable for ~30 days via restore_deleted (type "list"), which brings the items deleted with it back too. When the list still holds items the call refuses unless confirmDeleteItems is true, so the blast radius is always named before it happens. The hub's own Tasks list and Life Admin cannot be deleted.

**Parameters**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `listId` | `string` | yes | The list's id (from list_lists). |
| `confirmDeleteItems` | `boolean \| null` | no | Required (true) when the list holds items: confirms deleting the list AND every item on it. Confirm with the user first. |

**Returns**

- `deleted` (`boolean`)
- `id` (`string`)
- `name` (`string`)
- `itemsDeleted` (`number`)

**Example**

```json
{
  "method": "tools/call",
  "params": {
    "name": "delete_list",
    "arguments": {
      "listId": "<listId>"
    }
  }
}
```

## Items

What lists hold: a task, a note, a row of a reading list are all items with a title, a body as Markdown and values for their list's properties. List, read, query, create many at once, update by block handle, move between lists, delete.

### list_items

**List items** · `Read-only`

List, filter and search items. Omit listId for the Tasks set — every item on a list that keeps a status and a due date (the Tasks list and every list made for tasks), ordered by due date then creation, completed tasks left out by default. Pass listId for one list's items, whatever its shape: a notes list's prose, a reading list's rows. Each row carries the item's title, body as Markdown, status and due date where its list keeps them, values keyed by property id, and its list. get_item reads one item in full with handles for editing, and is the call when the person asks to see, open or show one item; query_items filters, counts and sums by property. A read that repeats on a schedule passes `changedSince`, the `nextChangedSince` of its previous read: only what moved since comes back on the person's own lists, deletions included, one call per cycle instead of the whole list.

**Parameters**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `listId` | `string` | no | One list's items: a list id (from list_lists or get_context), or the word "tasks" (the Tasks list, the unsorted pool) or "notes" (the Notes list, made afresh when the user deleted theirs). Omit for the Tasks set. |
| `changedSince` | `string` | no | An ISO 8601 instant (exclusive), or the `nextChangedSince` of the previous read verbatim. The changes feed for a worker that polls: every item of the list (or of the person's own lists that keep the task columns, trashed and archived ones included) whose record moved after it — edits, completions, archives, restores, deletions — oldest change first, the deleted ones as `deleted` tombstones, then `hasMore` and `nextChangedSince` to pass next time. Items shared with the person are not in the feed (list_items without changedSince reads them). `query` is refused beside it; the other filters and `sort` do not apply. |
| `ids` | `string[]` | no | Specific item ids to fetch (the other filters still apply). |
| `query` | `string` | no | Free-text search across title and body. |
| `taskStatus` | `"todo" \| "inProgress" \| "completed"[]` | no | Filter to these statuses, on lists that keep one. Omit for the default active set (excludes completed). |
| `dueAfter` | `string` | no | ISO 8601 instant — only items due on/after this (inclusive). |
| `dueBefore` | `string` | no | ISO 8601 instant — only items due before this (exclusive). Today = dueAfter today 00:00 local, dueBefore tomorrow 00:00 local; overdue = dueBefore today 00:00 alone. |
| `createdAfter` | `string` | no | ISO 8601 instant — only items created on/after this. |
| `createdBefore` | `string` | no | ISO 8601 instant — only items created before this (exclusive). |
| `updatedAfter` | `string` | no | ISO 8601 instant — only items last edited on/after this. A poll that wants deletions too uses `changedSince` instead. |
| `updatedBefore` | `string` | no | ISO 8601 instant — only items last edited before this (exclusive). |
| `completedAfter` | `string` | no | ISO 8601 instant — only items completed on/after this. Implies completed items unless taskStatus says otherwise. |
| `completedBefore` | `string` | no | ISO 8601 instant — only items completed before this (exclusive). |
| `sort` | `"due" \| "created" \| "updated" \| "completed"` | no | Row order. Default 'due' (due date, then creation); a timestamp sort returns newest first. |
| `limit` | `integer` | no | Max results (default 50). (1 to 200) |
| `includeImageUrls` | `boolean` | no | true additionally returns a short-lived signed `url` per attachment so the images can be viewed. Off by default. |

**Returns**

- `count` (`number`)
- `listId` (`string | null`)
- `listName` (`string | null`)
- `listIcon` (`string | null`): The list's own icon, an emoji, when it has one; null for the Tasks set.
- `properties` (`object[]`): The list's own properties, on a read of one list that has some.
- `items` (`object[]`)
- `deleted` (`object[]`): With changedSince: the items deleted since, as tombstones.
- `serverTime` (`string`): With changedSince: the server's clock when this read began.
- `hasMore` (`boolean`): With changedSince: more changed than `limit`; continue with `nextChangedSince`.
- `nextChangedSince` (`string`): With changedSince: what to pass as the next call's changedSince, verbatim (an instant, or the last row's stamp and id while more is pending).
- `links` (`object`): The roots of a row's links: `<webOrigin>/artifacts/<id>` is the item's page in Koma, `<appScheme>://artifacts/<id>` the same item in the Koma Mac app.

**Example**

```json
{
  "method": "tools/call",
  "params": {
    "name": "list_items",
    "arguments": {}
  }
}
```

### get_item

**Get item** · `Read-only`

Read one item in full by its id — the thing to read before working on it, the call when the person asks to see, open or show one item (search and list_items find it; this shows it), and the companion to search, which returns only the matched passage. Returns the item with `body` (the body as Markdown with a short handle in front of every block; update_items edits target those handles), `bodyVersion` (what a whole-body rewrite is pinned to), its status and due date where its list keeps them, `values` by property id with `cells` by property name beside them, its list, `guidance` (a line about working this item: its status, what the person wrote in its chat since an agent last posted, where the work goes) and, for an item a meeting was recorded into, the attributed transcript once its recording is done, with `summary` and `taskCandidates`.

**Parameters**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `itemId` | `string` | yes | The item's id (from list_items, query_items, search or get_context). |
| `includeImageUrls` | `boolean` | no | true additionally returns a short-lived signed `url` per attachment so the images can be viewed. Off by default. |

**Returns**

- `id` (`string`)
- `title` (`string | null`)
- `body` (`string | null`): The body as Markdown; with a short handle in front of every block on a read made for editing.
- `bodyVersion` (`string`): A fingerprint of the body as read; a whole-body `rewrite` names it as `baseVersion`.
- `taskStatus` (`string | null`): On a list that keeps a status.
- `dueAt` (`string | null`): On a list that keeps a due date.
- `hasDueTime` (`boolean | null`)
- `reminderAt` (`string | null`)
- `completedAt` (`string | null`)
- `values` (`object`): The item's values keyed by property id; a select value is an option id.
- `cells` (`object of string`): The item's values by property NAME, as text, where its list has properties of its own.
- `isSharedWithMe` (`boolean`): Shared with the person by its owner; `editable` says what update_items admits on it.
- `editable` (`"all" | "titleAndBody"`): On a row shared with the person: `titleAndBody` for an item shared with them one by one (its status, due date, values and images are its owner's; update_items refuses them by name), `all` for an item on a list shared with them (every field but the owner's favorite).
- `listId` (`string | null`)
- `listName` (`string | null`)
- `listIcon` (`string | null`): The list's own icon, an emoji, when it has one.
- `createdAt` (`string | null`)
- `updatedAt` (`string | null`)
- `editedAt` (`string | null`)
- `archivedAt` (`string | null`)
- `recordingStatus` (`string`)
- `attachments` (`object[]`)
- `bodyImages` (`object[]`): The pictures the body shows (`![…](koma://attachment/<bucketPath>)`), whether or not they are attachments, with the size each was stored at (null when unknown); with includeImageUrls, a short-lived signed url on each.
- `guidance` (`string`): How to work this item right now: its status, what the person wrote in its chat since an agent last posted, where the work goes.
- `label` (`string`): For an item with no title: its first non-empty value, else its list's name.
- `properties` (`object[]`): The list's own properties, so a value can be written back by id.
- `webUrl` (`string`): The item's page in Koma, to open in a browser.
- `appUrl` (`string`): The item in the Koma Mac app: the app's own link scheme (yamo://artifacts/:id; yamo-staging:// against staging).
- `transcript` (`string`)
- `recording` (`object`)
- `summary` (`object`)
- `taskCandidates` (`object[]`)

**Example**

```json
{
  "method": "tools/call",
  "params": {
    "name": "get_item",
    "arguments": {
      "itemId": "<itemId>"
    }
  }
}
```

### query_items

**Query items** · `Read-only`

Filter, sort, count or sum the items of ONE list by its properties — exact numbers instead of eyeballing a dump: "how many are unread", "expenses in March", "the wines rated 5". `where` clauses AND-combine on a property by id or name (on a list that keeps them, `status` and `dueDate` are properties too); a select value may be its label. mode 'list' (default) returns the matching items, paged with offset and limit; 'count' how many match; 'sum' the total of `sumPropertyId` across the matches. Archived items are left out unless includeArchived: true; each item reports its archivedAt.

**Parameters**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `listId` | `string` | yes | The list to query: a list id (from list_lists or get_context), or the word "tasks" (the Tasks list, the unsorted pool) or "notes" (the Notes list, made afresh when the user deleted theirs). |
| `where` | `object[] \| null` | no | Filter clauses, AND-combined. Omit for every item. |
| `sort` | `object \| null` | no | Sort order. Omit for the list's default (newest first). |
| `mode` | `"list" \| "count" \| "sum" \| null` | no | 'list' (default) returns matching items; 'count' how many match; 'sum' totals `sumPropertyId` across matches. |
| `sumPropertyId` | `string \| null` | no | For mode 'sum': the numeric property to total (its stable id or name). |
| `createdAfter` | `string \| null` | no | ISO 8601 instant — items added on/after this. |
| `createdBefore` | `string \| null` | no | ISO 8601 instant — items added before this (exclusive). |
| `updatedAfter` | `string \| null` | no | ISO 8601 instant — items last edited on/after this. A read that repeats on a schedule passes the instant of its previous read here, or uses list_items' `changedSince`, which also carries deletions. |
| `updatedBefore` | `string \| null` | no | ISO 8601 instant — items last edited before this (exclusive). |
| `includeArchived` | `boolean \| null` | no | true also includes archived items (hidden from every list by default), so one can be brought back with update_items. |
| `limit` | `integer \| null` | no | mode 'list': max items per page (default 50). |
| `offset` | `integer \| null` | no | mode 'list': items to skip — page through a big list with offset + limit until hasMore is false. |
| `includeImageUrls` | `boolean \| null` | no | mode 'list': true additionally returns a short-lived signed `url` per attachment. |

**Returns**

- `mode` (`"list" | "count" | "sum"`)
- `listId` (`string`)
- `listName` (`string`)
- `listIcon` (`string | null`): The list's own icon, an emoji, when it has one.
- `count` (`number`): How many items match.
- `sum` (`number`)
- `sumPropertyId` (`string`)
- `properties` (`object[]`)
- `items` (`object[]`)
- `offset` (`number`)
- `hasMore` (`boolean`)

**Example**

```json
{
  "method": "tools/call",
  "params": {
    "name": "query_items",
    "arguments": {
      "listId": "<listId>"
    }
  }
}
```

### create_items

**Create items** · `Adds data` · `Reaches outside Koma`

Create items on one list, many in one call (1 to 100): a to-do or a dictated list of them on the Tasks list, a note on the Notes list, rows of a reading list or a CRM. Each entry carries a title, a body as Markdown, and `values` for the list's own properties as {propertyId, value} pairs (ids or names from list_lists; a select value may be its label or option id, a multiSelect value an array of them; an unknown label becomes a new option). On a list that keeps a status and a due date an entry may set taskStatus and dueAt. The items are stored as written and indexed for search; no AI pass runs unless `enrich` is true, which on a tasks list derives the title and due date from the words. An entry's `externalId` (the caller's own id) makes re-sending safe: the same externalId returns the item already made, under `existing`. With `matchOn`, an entry whose named values match an existing item fills that item's empty values, body and images and overwrites nothing (changing a filled value is update_items' job); without it every entry is inserted. Images come as `imageUrls` (a Koma storage path from create_image_upload, or a public https image URL the server downloads); failures come back in `imageFailures`. One bad entry never fails the batch; it is reported under `failed` with its reason.

**Parameters**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `listId` | `string` | no | The list every item lands on: a list id (from list_lists or get_context), or the word "tasks" (the Tasks list, the unsorted pool) or "notes" (the Notes list, made afresh when the user deleted theirs). Omit for the Tasks list. |
| `items` | `object[]` | yes | Every item to create, in one call. (up to 100 items) |
| `matchOn` | `string[] \| null` | no | Property ids or names that identify an existing item. When given, an entry whose listed values all match an existing item is not added again: the existing item gains the entry's values for its empty cells, its body if it had none, and its images, and keeps every cell it already had; matching is exact. Omit to always insert — no property is a natural key, so there is no default dedup. |
| `enrich` | `boolean \| null` | no | Run Koma's background AI pass on each item of a tasks list (title cleanup, due date and list suggestions). Default false: the items are stored as written. |

**Returns**

- `listId` (`string`)
- `listName` (`string`)
- `listIcon` (`string | null`): The list's own icon, an emoji, when it has one.
- `properties` (`object[]`): The list's own properties, when it has some.
- `items` (`object[]`)
- `added` (`number`): Items inserted by this call.
- `links` (`object`): The roots of a row's links: `<webOrigin>/artifacts/<id>` is the item's page in Koma, `<appScheme>://artifacts/<id>` the same item in the Koma Mac app.
- `mergedIds` (`string[]`): Existing items an entry was merged into through matchOn.
- `existing` (`object[]`)
- `failed` (`object[]`)
- `unknownKeys` (`string[]`)
- `imagesAttached` (`number`)
- `imageFailures` (`object[]`)

**Example**

```json
{
  "method": "tools/call",
  "params": {
    "name": "create_items",
    "arguments": {
      "items": [
        {}
      ]
    }
  }
}
```

### update_items

**Update items** · `Updates or removes existing data` · `Safe to retry` · `Reaches outside Koma`

Update items, many in one call, each with its own title, body edits and values; the status, due date, archive and favorite flags apply to every item in the call. Only the fields passed change; null leaves a field as it is. The body is edited with `edits` against the handles get_item returns in `body` — replace, insert, delete, setChecked, move, replaceText, or rewrite pinned to `bodyVersion` — applied in order, all or nothing; a refused call writes nothing on that item and returns the current body with fresh handles. The older way, `body` with the call's merge `mode` (append by default, prepend, insertAfter with `anchor`, replace with confirmReplace: true), still works; an item uses one or the other. `values` MERGE into the item (only the properties sent change; "" clears one; an unknown property is an error naming the valid ones). `imageUrls` add images (clearImages: true drops the old ones first). taskStatus and dueAt apply only on a list that keeps them ("none" clears the due date and its reminder). Items are written in order; a refusal stops the batch and names the items already written, so re-send only the rest. Returns each item, with `body`, `bodyVersion` and `applied` after a body write.

**Parameters**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `items` | `object[]` | yes | Every item to update, in one call. (up to 200 items) |
| `mode` | `"prepend" \| "append" \| "replace" \| "insertAfter" \| null` | no | Legacy: how each item's `body` merges: 'append' (default, at the bottom), 'prepend' (at the top), 'insertAfter' (right after the line named in `anchor`), or 'replace' (swap the whole body — only when the user explicitly asked to rewrite it; requires confirmReplace: true). |
| `anchor` | `string \| null` | no | For mode 'insertAfter' only: a verbatim snippet of the existing line to insert after. Errors if not found. |
| `confirmReplace` | `boolean \| null` | no | Required (true) for mode 'replace': confirms the user explicitly asked to swap the WHOLE body, deleting everything in it. Never pass it on the user's behalf without that explicit ask. |
| `taskStatus` | `"todo" \| "inProgress" \| "completed" \| null` | no | todo, inProgress or completed, on a list that keeps a status; applies to every item in the call. Status transitions report progress. |
| `dueAt` | `string \| null` | no | ISO 8601 timestamp, on a list that keeps a due date; "none" clears it; applies to every item in the call. |
| `archived` | `boolean \| null` | no | true sets the item(s) aside (hidden from every list, kept and reversible); false brings them back. |
| `favorited` | `boolean \| null` | no | true pins the item(s) in the app's Favorites; false unpins them. |

**Returns**

- `updated` (`number`)
- `items` (`object[]`)
- `imagesAttached` (`number`)
- `imageFailures` (`object[]`)
- `links` (`object`): The roots of a row's links: `<webOrigin>/artifacts/<id>` is the item's page in Koma, `<appScheme>://artifacts/<id>` the same item in the Koma Mac app.

**Example**

```json
{
  "method": "tools/call",
  "params": {
    "name": "update_items",
    "arguments": {
      "items": [
        {
          "itemId": "<itemId>"
        }
      ]
    }
  }
}
```

### move_items

**Move items** · `Updates or removes existing data` · `Safe to retry`

Move items onto another list: a task out to the Tasks list ("tasks"), a note onto the Notes list ("notes"), anything onto a list by id. Each item keeps its id, body, chat and history; its values follow their properties by id, then by name and type, select values by label. A value the destination list has no place for would be DROPPED: a first call that would drop values answers a preview (preview: true, droppedValues) and moves nothing; the same call with acknowledgeDataLoss: true then moves. The status and due date ride along unseen onto a list that keeps neither and show again on the way back. Items that are not the user's own are reported under `refused`, never moved.

**Parameters**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `itemIds` | `string[]` | yes | Ids of the items to move. (up to 100 items) |
| `listId` | `string` | yes | The destination list: a list id (from list_lists or get_context), or the word "tasks" (the Tasks list, the unsorted pool) or "notes" (the Notes list, made afresh when the user deleted theirs). |
| `acknowledgeDataLoss` | `boolean \| null` | no | true ONLY on a repeat call, after a preview reported values the destination list has no place for and you told the user what will be lost. |

**Returns**

- `preview` (`boolean`)
- `listId` (`string`)
- `listName` (`string | null`)
- `items` (`object[]`)
- `droppedValues` (`object[]`)
- `refused` (`string[]`)

**Example**

```json
{
  "method": "tools/call",
  "params": {
    "name": "move_items",
    "arguments": {
      "itemIds": [
        "<itemIds>"
      ],
      "listId": "<listId>"
    }
  }
}
```

### delete_items

**Delete items** · `Updates or removes existing data` · `Safe to retry`

Delete items by id, up to 50 per call. SOFT delete: every item stays recoverable for ~30 days via restore_deleted (type "item") before it is purged, and drops out of search. Returns the deleted items; ids that are not the user's own items are reported under `refused` and the rest still delete.

**Parameters**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `itemIds` | `string[]` | yes | The items' ids. Up to 50 per call. (up to 50 items) |

**Returns**

- `deleted` (`number`)
- `items` (`object[]`)
- `refused` (`string[]`)

**Example**

```json
{
  "method": "tools/call",
  "params": {
    "name": "delete_items",
    "arguments": {
      "itemIds": [
        "<itemIds>"
      ]
    }
  }
}
```

### create_image_upload

**Create image upload** · `Adds data`

Get pre-signed URLs to upload images DIRECTLY into Koma storage — the reliable alternative to passing third-party links in imageUrls (those must stay fetchable until the server downloads them; short-lived signed links often expire first). For each slot: HTTP PUT the raw image bytes to uploadUrl with the matching Content-Type header (valid ~2 hours), then pass its bucketPath as an imageUrls entry in create_items / update_items. Keep images at or under 10 MB (maxBytes). Up to 10 slots per call.

**Parameters**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `mimeType` | `"image/png" \| "image/jpeg" \| "image/heic" \| "image/webp"` | yes | The image type you will upload (all slots in one call share it). |
| `count` | `integer` | no | How many upload slots (default 1). (1 to 10) |

**Returns**

- `uploads` (`object[]`)
- `maxBytes` (`number`)
- `validForSeconds` (`number`)

**Example**

```json
{
  "method": "tools/call",
  "params": {
    "name": "create_image_upload",
    "arguments": {
      "mimeType": "image/png"
    }
  }
}
```

## Search

Finds items and lists by meaning or keyword, with the best-matching passage per item.

### search

**Search items and lists** · `Read-only`

Search the user's Koma workspace — their items (tasks, notes, the rows of every list they keep) and their lists — by meaning or keyword (hybrid semantic + keyword retrieval). Use this when the user asks about their own information, plans or anything they may have saved, and before adding something that may already exist. Their wording often won't match their notes' wording; the semantic arm bridges that gap (and across languages). Returns the best-matching passage per item, each with its list; get_item returns an item in full. An empty result means nothing relevant is saved. Not for general web knowledge.

**Parameters**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `query` | `string` | yes | Natural-language query — what the user is trying to find, in their words. |
| `limit` | `integer` | no | Max results (default 10). (1 to 20) |
| `after` | `string` | no | Only items CREATED on/after this ISO 8601 timestamp. Use when scoping by when it was saved ("last week", "in March"). |
| `before` | `string` | no | Only items CREATED before this ISO 8601 timestamp (exclusive). Pair with `after` to bound a window. |

**Returns**

- `count` (`number`)
- `results` (`object[]`)

**Example**

```json
{
  "method": "tools/call",
  "params": {
    "name": "search",
    "arguments": {
      "query": "<query>"
    }
  }
}
```

## Chats

The chat on an item, as the room an agent shares with the person: read what was said, post a note under the agent's name.

### read_chat_messages

**Read chat messages** · `Read-only`

Read the recent messages in an item's chat: what the user said there, what Koma replied, and what any agent posted with post_chat_message. Pass `since` to read only what arrived after a moment you already saw; a read that repeats on a schedule passes the `createdAt` of the last message it saw every time. Empty when the item has no chat yet.

**Parameters**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `artifactId` | `string` | yes | The item's id. |
| `since` | `string` | no | ISO 8601 instant. Only messages created after it are returned, oldest first: the `createdAt` of the last message you saw. |
| `limit` | `integer` | no | Max messages (default 20). (1 to 50) |

**Returns**

- `sessionId` (`string | null`)
- `messages` (`object[]`)
- `truncated` (`boolean`)

**Example**

```json
{
  "method": "tools/call",
  "params": {
    "name": "read_chat_messages",
    "arguments": {
      "artifactId": "<artifactId>"
    }
  }
}
```

### post_chat_message

**Post chat message** · `Updates or removes existing data` · `Safe to retry`

Post a message into an item's chat as the calling agent: an action taken outside Koma with its link, or the one question the work is blocked on. The user sees it on every device as an unread reply on the item and as a line in their main conversation, and the agent cannot take it back, so a post per step, or a note that work is finished, reads as noise. Set `needsInput` when the work is blocked on their answer. The same `messageKey` posted twice lands once.

**Parameters**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `artifactId` | `string` | yes | The item's id. |
| `message` | `string` | yes | The message, as Markdown. (up to 20000 characters) |
| `agentName` | `string` | no | How the agent is named in the chat (default "Your agent"). (up to 60 characters) |
| `needsInput` | `boolean` | no | True when the message is a question the work waits on. |
| `messageKey` | `string` | no | Idempotency key: a retry with the same key updates the same message. (up to 120 characters) |

**Returns**

- `id` (`string`)
- `sessionId` (`string`)
- `createdAt` (`string`)

**Example**

```json
{
  "method": "tools/call",
  "params": {
    "name": "post_chat_message",
    "arguments": {
      "artifactId": "<artifactId>",
      "message": "<message>"
    }
  }
}
```

## Trash

Every delete is soft. The trash lists what was deleted and restores one item or list per call for about 30 days.

### list_deleted

**List deleted items and lists (trash)** · `Read-only`

The trash: everything soft-deleted in the last ~30 days — items and lists — newest first, each with the moment it is purged forever (purgesAt). Anything listed here can be brought back with restore_deleted. Filter by type, or omit `type` for both.

**Parameters**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `type` | `"item" \| "list"` | no | Only this kind. Omit for both. |
| `limit` | `integer` | no | Max entries per kind (default 25). (1 to 100) |

**Returns**

- `count` (`number`)
- `items` (`object[]`)

**Example**

```json
{
  "method": "tools/call",
  "params": {
    "name": "list_deleted",
    "arguments": {}
  }
}
```

### restore_deleted

**Restore deleted item or list** · `Adds data` · `Safe to retry`

Bring back one soft-deleted item or list from the trash (see list_deleted). Restoring a list also brings back the items deleted with it; an item whose list is still in the trash can't come back alone (restore the list first). An item whose list is gone for good lands on the hub's default list for what it was (movedToDefaultList: true). Restores one thing per call. If it is already live the call succeeds with alreadyLive: true.

**Parameters**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `type` | `"item" \| "list"` | yes | The entry's type, as list_deleted reported it. |
| `id` | `string` | yes | The deleted item's or list's id. |

**Returns**

- `restored` (`boolean`)
- `alreadyLive` (`boolean`)
- `type` (`string`)
- `id` (`string`)
- `title` (`string | null`)
- `restoredItems` (`number`)
- `movedToDefaultList` (`boolean`)

**Example**

```json
{
  "method": "tools/call",
  "params": {
    "name": "restore_deleted",
    "arguments": {
      "type": "item",
      "id": "<id>"
    }
  }
}
```

## Automations

Standing orders Koma runs on a schedule. Read them, read what their runs found, and start one when the user asks.

### list_automations

**List automations** · `Read-only`

List the user's automations — standing orders Koma runs on its own, on a schedule or on demand. Returns each one's id, name, what it does, status (active / paused / draft), when it runs, the next run, and how the last run ended. Use it when the user asks what runs on its own, when something runs next, or before reading or starting a run.

**Parameters**

This tool takes no parameters.

**Returns**

- `count` (`number`)
- `automations` (`object[]`)

**Example**

```json
{
  "method": "tools/call",
  "params": {
    "name": "list_automations",
    "arguments": {}
  }
}
```

### get_automation_runs

**Get automation runs** · `Read-only`

Read one automation's recent runs, newest first: when each ran, how it ended, what it wrote (one line per action), the message it left for the user, and any error. Use it for "what did my morning brief find", "why did it fail", or to read the result of a run started with run_automation once it has finished.

**Parameters**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `automationId` | `string` | yes | The automation's id (from list_automations or get_context). |
| `limit` | `integer` | no | How many runs, newest first (default 5, max 20). (1 to 20) |

**Returns**

- `automation` (`object`)
- `runs` (`object[]`)

**Example**

```json
{
  "method": "tools/call",
  "params": {
    "name": "get_automation_runs",
    "arguments": {
      "automationId": "<automationId>"
    }
  }
}
```

### run_automation

**Run automation now** · `Updates or removes existing data` · `Reaches outside Koma`

Start one of the user's automations now — the same as Run now on its page in Koma. Use it only when the user asks to run a specific automation. The run happens inside Koma with the user's connected apps and can take a minute; its result lands in the user's Koma chat, not in this conversation. Read the outcome afterwards with get_automation_runs. Refused for a draft, while the same automation is already running, or once the daily run limit is reached.

**Parameters**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `automationId` | `string` | yes | The automation's id (from list_automations or get_context). |

**Returns**

- `id` (`string`)
- `name` (`string`)
- `runId` (`string`)
- `status` (`string`)

**Example**

```json
{
  "method": "tools/call",
  "params": {
    "name": "run_automation",
    "arguments": {
      "automationId": "<automationId>"
    }
  }
}
```

