Tools & Annotations
The complete list comes live from tools/list. Below are the most important concepts for working with the list/task tools.
Filters on list_list_items
Server-side filters save you from post-filtering and reduce the response size:
| Parameter | Effect |
|---|---|
state | open / done / all |
assigned_to_me | only items assigned to me (no get_me needed) |
due_within_days | due soon (including overdue) |
due_before | due before an ISO date |
sort | priority / due_date / created / modified |
compact | lean response (fewer tokens) |
{"name":"list_list_items",
"arguments":{"state":"open","assigned_to_me":true,"compact":true}}Useful dedicated tools
get_my_open_items— "What's on my plate?" (overdue → due → priority)complete_list_item/complete_list_items— check off (single/bulk)list_recent_changes— sync/polling: what has changed sincesinceget_metadata— valid status/priority/scope valuesget_item_dashboard— a task's dashboard page (requirements, outline) with the numbering the UI shows;get_list_itemdoes not include itsearch_ai_messages— search/filter the Claude Code AI chat historyget_ai_chat_history— read the full AI chat history of an item (no truncation)get_item_ai_status— run state of an item: running / waiting / done / crashed, and since whenget_item_ai_summaries— read the closing summaries of runs (counterpart topost_activity_summary)
search_ai_messages
Searches/filters the team's Claude Code AI chat history (conversations attached to list items/lists):
| Parameter | Effect |
|---|---|
query | free-text search in the message content (optional — without query it just filters/lists) |
listId | restrict to a list — UUID, SID, or list number ("177"/"#177") |
itemId | restrict to a single item — UUID, SID, or "#<listNum>.<itemNum>" (e.g. "#177.252", as shown in the UI/commit titles); a bare item number only works together with listId, since list_items.num is only unique within a list |
userId | only conversations created by this user |
role | user / assistant / tool |
dateFrom / dateTo | date range (ISO 8601) |
limit / offset | pagination (max 200) |
{"name":"search_ai_messages",
"arguments":{"itemId":"#177.252","query":"rate limit","role":"assistant"}}Visibility is hard-wired, not a role bypass: a conversation is either public (visible to anyone with access to the underlying item/list) or private (default — visible only to its own creator, no bypass for admin/owner). Details: public-api/docs/MCP-TOOL-AI-MESSAGES.md.
get_ai_chat_history
Reads the full AI chat history of a single item — across all its threads, with the complete message content instead of a truncated snippet:
| Parameter | Effect |
|---|---|
itemId | UUID or SID of the item (required) |
dateFrom / dateTo | date range (ISO 8601) — restrict this so you don't have to load the entire history every time |
{"name":"get_ai_chat_history",
"arguments":{"itemId":"<UUID>","dateFrom":"2026-07-04T00:00:00Z"}}Same visibility rule as search_ai_messages (public vs. private per thread, no role bypass). Details: public-api/docs/MCP-TOOL-AI-CHAT-HISTORY.md.
get_item_ai_status
Reads the run state of one or more items — the channel to poll while another item works on an order. get_ai_chat_history tells you what a run said; this tells you whether it is still running.
| Parameter | Effect |
|---|---|
itemIds | UUID, SID or reference #<listNum>.<itemNum> (e.g. #216.114), max 200 |
listId | Alternative: every item of a list that has an AI thread. UUID, SID or #<listNum> |
One state per item to branch on — precedence waiting > running > queued > error > done > idle > no_thread:
state | Meaning |
|---|---|
waiting | The run is waiting for an answer (questionText says what for). Beats running, because it is the reason nothing is progressing |
running | Running, heartbeat fresh |
stale | The DB says "running" but the last sign of life is older than staleAfterMs (35 min) — treat as probably dead |
queued | Order armed but not started (pending orders deliberately never time out) |
needs_decision | The run finished, the task did not: a decision is missing (decisionText). Answering means placing a new order — unlike waiting, where a live run is paused on a dialog. Set by report_decision_needed |
error / done | finished; errorMsg, doneAt |
idle | Thread exists, nothing running right now |
no_thread | No AI has ever worked on this item (for you) |
Plus statusAt / doneAt / liveAt — the only timestamps of a run that survive a restart. list_recent_changes and list_items.modified are blind to AI runs (see api/lib/claudeCode/util/aiMetaTimestamps.js) and cannot be used for this.
{"name":"get_item_ai_status",
"arguments":{"itemIds":["#216.196","#216.199"]}}A projection of api/lib/claudeCode/thread/items.js — the same derivation that feeds the AI pill on the item. Two differences: it cleans up nothing (a read tool does not write; orphaned runs are reported as stale instead of being swept away silently), and the heartbeat is checked for freshness. Run state is per creator — other people's runs are not visible.
report_decision_needed
The write path to needs_decision. An unattended run (started from a queued order, nobody watching) must not use ask_user: nobody sees the dialog and the run hangs until the stale sweep. It calls this tool instead, finishes everything that does not depend on the decision, and ends with the same findings in text.
| Parameter | Effect |
|---|---|
itemId | UUID, SID or #<listNum>.<itemNum> |
decision | What has to be decided, with the options — written so it can be acted on without reading the transcript |
resolved | true clears an existing note (the decision has been made) |
{"name":"report_decision_needed",
"arguments":{"itemId":"#216.114","decision":"PR workflow or auto-merge? Both touch finalizeWorktree."}}In an interactive session use ask_user instead — a human is present there, and answering continues the same run without rebuilding its context.
Why the tool is needed at all: findings that live only in the closing message do not exist for a machine. The run ends normally, its queue row goes to done, and the status channel reported done — an orchestrator considered the task finished although its own summary said otherwise (observed in the field, #216.197). Deliberately no pattern matching on model output: a matcher over free-form text fails silently as soon as the wording drifts.
A new run on the same item clears the note automatically.
get_item_ai_summaries
Reads the closing summaries from the Activity feed (list_history, action ai_summary) — the read side of post_activity_summary. The right channel for an orchestrator: a few sentences per item instead of a whole transcript.
| Parameter | Effect |
|---|---|
itemIds | UUID or SID, max 200 |
listId | Alternative: every item of a list that has a summary |
since | Only summaries from this timestamp on (ISO 8601) — use when polling |
{"name":"get_item_ai_summaries",
"arguments":{"itemIds":["<UUID>"],"since":"2026-08-23T07:00:00Z"}}There is exactly one entry per item and author: a later run overwrites its own summary and refreshes created. For the history, use get_ai_chat_history. No creator filter — the Activity feed is team-visible in the UI, and post_activity_summary writes nothing for a private conversation anyway; isOwn shows the origin.
Profiles & progressive disclosure
The tool schema block goes into every request an agent makes — and one turn consists of several requests. Carrying all tools permanently therefore costs tokens at every step. A client can request a curated profile:
x-liza-mcp-profile: agent| Profile | Contents |
|---|---|
| (no header) | all role-permitted tools |
agent | the tools a coding agent needs in almost every run: read & change lists/items (incl. bulk), post_activity_summary, get_me, get_widget_spec, search_memory/save_memory |
onboarding | minimal set for the onboarding guide: check off items, create lists/items, invite_user, search_docs, get_me, post_chat_message |
Everything outside the profile stays reachable through two meta tools:
| Tool | Purpose |
|---|---|
list_liza_tools | Catalogue of the tools not loaded, with description and input schema. Optional query filter (e.g. "crm", "calendar"). |
call_liza_tool | Invokes any tool by name: { name, arguments }. Role and argument schema are checked exactly as for a direct call. |
{"name":"call_liza_tool",
"arguments":{"name":"schedule_task",
"arguments":{"title":"Weekly report","action_type":"reminder",
"rrule":"FREQ=WEEKLY;BYDAY=MO","message":"Write the report"}}}This keeps the schema budget small without making any tool unreachable. A client without token worries simply omits the header.
Context headers
Three optional headers tell the server which conversation a call comes from. Tools use them as defaults instead of forcing you to pass them:
| Header | Effect |
|---|---|
x-liza-conversation | Current AI conversation (scope_key). schedule_task uses it to plan "for this conversation" without the client knowing an ID. |
x-liza-provider | The conversation's AI engine (claude, codex, liza, …). Default provider for scheduled AI tasks. |
x-liza-model | The concrete model. Stored as ai_model on chat blocks the AI posts and shown in the UI. |
Annotations
Every tool carries behavior hints in tools/list, so that clients can allow read tools automatically and warn before destructive ones:
| Tool | Type |
|---|---|
list_list_items | read-only |
update_list_item | write · idempotent |
delete_list_item | destructive |
readOnlyHint, destructiveHint, idempotentHint, openWorldHint.
Pagination & compact
All list tools support compact:true. Paginated tools return has_more — after that, increase offset until has_more:false.