# Tickets

## List tickets: `list_tickets`

Returns a project's tickets, newest first, with id and number.

| Argument | Meaning |
|---|---|
| `status` | a status value of the project |
| `assignee` | a user id, or `me` for yourself |
| `tag` | name of a tag |
| `q` | full-text search in title and body |
| `page`, `per_page` | page, at most 100 per page |

<div class="docs-callout docs-callout--warning">
  <div class="docs-callout__title">Status belongs to the project</div>
  <p>Every project defines its own statuses. A guessed value like <code>open</code> simply returns zero hits in a project that says <code>offen</code>. The valid values are in <code>meta.available_statuses</code> of a call without a filter. What a status means is in <code>status_functions</code>, such as <code>is_open</code> or <code>is_completed</code>.</p>
</div>

## Read a ticket: `get_ticket`

The agent names either `ticket_id` or `number`, the number from the app such as `187` or `#187`.
A number is unique within one project only. If both are given, the id wins.

The answer holds the head fields, the description, custom fields, comments and attachments.

| Argument | Meaning |
|---|---|
| `posts_page`, `posts_per_page` | page of comments, at most 50 per page |
| `posts_order` | `oldest` (default) or `newest` |
| `attachments_page` | page of attachments, 10 each |
| `full_text` | the whole description, up to 100,000 characters |
| `post_id` | this one comment only, up to 100,000 characters |

Description and comments arrive cut to 8,000 characters at most. `full_text` fetches the
description, `post_id` one comment, each up to 100,000 characters. A ticket's attachment comes with up to 4,000 characters of its extracted text, there
is no way to get more. `text_status` says whether it is there:

| `text_status` | Meaning |
|---|---|
| `available` | the text is readable |
| `empty` | the file was read and holds no text, such as a scan |
| `unavailable` | not read yet, or reading failed, may work later |
| `unsupported` | Lalabase reads no text from this file type |

Files on a comment are listed there with name, type and size, their text does not come along.

## Create a ticket: `create_ticket`

| Argument | Meaning |
|---|---|
| `title` | required, one line, at most 255 characters |
| `description` | body of the ticket |
| `ticket_type` | type, default `support` |
| `summary` | one-line summary |
| `status` | initial status, a key from `meta.available_statuses` |

## Comment: `post_comment`

| Argument | Meaning |
|---|---|
| `ticket_id` | required, the ticket's id |
| `body` | required, the text |
| `format` | `html` (default) or `plain` for plain text |
| `is_private` | `true`: only you and the account admins see the comment |

A comment over MCP is a normal comment: it appears in the activity and triggers the same
notifications as one from the app. Markdown is not converted.

## Change: `update_ticket`

One call changes exactly one thing, otherwise Lalabase refuses it:

| Argument | Changes |
|---|---|
| `ticket_id` | nothing, but it is required: the id, a number does not work here |
| `title` | the title |
| `status` | the status, as a key from `meta.available_statuses`, not a display name |
| `add_assignee_ids`, `remove_assignee_ids` | the assignees, everybody else stays assigned; `me` means you, at most 50 ids |

To change status and assignees, the agent makes two calls. It changes the same things the same way
the board does.
