# История изменений (/ru/docs/wa/changelog)

Notable changes to `@wirecat/whatsapp-cli`. One section per version, newest first; versions follow
[semantic versioning](https://semver.org), so before `1.0.0` the command interface may still change.

## 0.8.0 — 24.10.2026 [#080--24102026]

### Added [#added]

* The owner-run `bin/live-oneshot-drop` can send its two test messages automatically with
  `--sender-profile`, using two explicitly confirmed accounts owned by the same person.

* **Session and setup receipts declare their actual provider schemas.** The complete contract audit checks them alongside shared entities.

* Preview a group or channel invite with `chats inspect`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-chats-inspect "Справочник команды: wa chats inspect") without joining it.

* `account sessions list`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-account-sessions-list "Справочник команды: wa account sessions list") shows linked device ids and marks this device. Names and last-active times are unavailable.

* `chats folders list`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-chats-folders-list "Справочник команды: wa chats folders list") and `show` read custom WhatsApp Lists and their chats from synced label state.

* Incoming community announcement comments are decrypted into their post's stored thread; `messages comments`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-messages-comments "Справочник команды: wa messages comments")
  reads the comments this device has received. Channels have no comments, and comment sending stays unavailable.

### Changed — may break callers [#changed--may-break-callers]

* The one-shot regression checks the receiver's store before restarting `serve`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-serve "Справочник команды: wa serve"); delivery only after restart
  is inconclusive. Lost messages and inconclusive checks now return nonzero.

* **Template lists use a query instead of a name flag.** Replace `bot templates list --name hello_world`[↗](/llms.mdx/docs/ru/wa/commands-bot/content.md#wa-bot-templates-list "Справочник команды: wa bot templates list") with
  `bot templates list name:hello_world`[↗](/llms.mdx/docs/ru/wa/commands-bot/content.md#wa-bot-templates-list "Справочник команды: wa bot templates list"). Meta applies the name predicate before paging; unsupported query fields
  are refused before a request. The retired flag has no compatibility alias.

* **Shared CLI contracts require explicit provider overrides.** Discovery includes the inherited definitions, schemas, reasons and exact deliberate differences. Contact activity filters with `scope:` and `at:`, and diagnostic run searches with `started_at:`. Unknown roster and webhook type lists are omitted instead of `null`.

### Fixed [#fixed]

* Permission-denied commands stay discoverable in CLI and MCP with current availability and reasons. Calls still enforce permissions; a listed command grants no execution access.

* The owner-run one-shot regression can pause and restore a persistent systemd user service, including one
  that selects its profile through its environment instead of a command argument.

* Full settings sync recovers stars and deletions as history updates, instead of presenting them as new live events.

* The installation guide explains how to allow the optional agent-skill hook with npm's scoped `--allow-scripts` flag.

## 0.7.0 — 24.10.2026 [#070--24102026]

### Added [#added-1]

* The first command at a terminal asks once for your languages, other WireCat tools to install, and whether
  commands and agents may only read. Pipes, agents and noninteractive runs skip the questions.
* Preview a group or channel invite with `chats inspect`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-chats-inspect "Справочник команды: wa chats inspect") without joining it.
* `account sessions list`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-account-sessions-list "Справочник команды: wa account sessions list") shows linked device ids and marks this device. Names and last-active times are unavailable.
* `chats folders list`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-chats-folders-list "Справочник команды: wa chats folders list") and `show` read custom WhatsApp Lists and their chats from synced label state.
* Incoming community announcement comments are decrypted into their post's stored thread; `messages comments`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-messages-comments "Справочник команды: wa messages comments")
  reads the comments this device has received. Channels have no comments, and comment sending stays unavailable.

### Changed — may break callers [#changed--may-break-callers-1]

* **Live JSON output uses item and end records.** `watch --jsonl`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-watch "Справочник команды: wa watch") wraps each message or event in
  `{ "type": "item", "data": … }`, uses snake_case fields and finishes with a `type: "end"` record.
  Update scripts that consumed bare messages or events.
* **Diagnostic search is `search runs`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-search-runs "Справочник команды: wa search runs").** Replace `runs search`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-runs "Справочник команды: wa runs") and its filter flags with query terms such as
  `status:failed`, `error_code:timeout`, `operation:messages.download` and `profile:work`.
* **Duplicate-task lists require `tasks duplicates list`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-tasks-duplicates-list "Справочник команды: wa tasks duplicates list").** The bare group shows help.
* **MCP exposes more writes through permission keys.** Commands that change future permissions or automation
  require `mcp.authority: allow`; raw Cloud API calls require `bot.api: allow`. Both default to `deny` over MCP.
  Store maintenance and other writes follow their command permissions.
* **Shared commands use canonical names without compatibility aliases.** Use `contacts info|events|aliases`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-contacts "Справочник команды: wa contacts"),
  `chats links`[↗](/llms.mdx/docs/ru/wa/commands-admin/content.md#wa-chats-links "Справочник команды: wa chats links"), `metadata show|sync`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-metadata "Справочник команды: wa metadata"), `tasks update`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-tasks-update "Справочник команды: wa tasks update"), `commands info`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-commands-info "Справочник команды: wa commands info"), `mcp add|check`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-mcp "Справочник команды: wa mcp") and
  `doctor reports show|create`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-doctor-reports "Справочник команды: wa doctor reports"). Models use `models list`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-models-list "Справочник команды: wa models list"), `models download`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-models-download "Справочник команды: wa models download") and `models keys`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-models-keys "Справочник команды: wa models keys").

### Fixed [#fixed-1]

* Commands to end other sessions or remove contacts are hidden from help, discovery and MCP because a linked
  WhatsApp device cannot perform them.
* **The agent skill describes explicit read receipts correctly.** Reading changes no read state;
  `chats mark-read`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-chats-mark-read "Справочник команды: wa chats mark-read") clears the unread mark and sends the receipt. The top help points to linking examples
  without promising Windows instructions that setup help does not contain.
* Full settings sync recovers stars and deletions as history updates, instead of presenting them as new live events.
* The installation guide explains how to allow the optional agent-skill hook with npm's scoped `--allow-scripts` flag.

## 0.6.0 — 24.10.2026 [#060--24102026]

### Added [#added-2]

* **`wa <profile> bot`: a WhatsApp Business number on Meta's Cloud API.** A bot profile keeps an access token in the
  system keychain (`bot auth set`[↗](/llms.mdx/docs/ru/wa/commands-bot/content.md#wa-bot-auth-set "Справочник команды: wa bot auth set")) and the number's ids as settings (`config set --bot phone_number_id …`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-config-set "Справочник команды: wa config set")). `bot me`[↗](/llms.mdx/docs/ru/wa/commands-bot/content.md#wa-bot-me "Справочник команды: wa bot me")
  names the number; `bot api <operation>`[↗](/llms.mdx/docs/ru/wa/commands-bot/content.md#wa-bot-api "Справочник команды: wa bot api") runs any of 63 Cloud API operations generated from Meta's OpenAPI file, and
  asks before the ones that cannot be undone, such as `register-phone-number`. It never links a device or starts the
  engine. What to watch for: never register a number whose WhatsApp you use on a phone — that deletes its account.
* **A bot sends text, replies, files and templates.** `bot messages send`[↗](/llms.mdx/docs/ru/wa/commands-bot/content.md#wa-bot-messages-send "Справочник команды: wa bot messages send") writes to a phone number in digits or to
  `user:<id>`; a file goes up once and is sent by its media id. `bot templates list`[↗](/llms.mdx/docs/ru/wa/commands-bot/content.md#wa-bot-templates-list "Справочник команды: wa bot templates list") and `bot templates send <chat> <name> [language]`[↗](/llms.mdx/docs/ru/wa/commands-bot/content.md#wa-bot-templates-send "Справочник команды: wa bot templates send") cover the approved messages, the only kind WhatsApp delivers more than 24 hours after a person
  wrote. `bot media download <id> --output <file>`[↗](/llms.mdx/docs/ru/wa/commands-bot/content.md#wa-bot-media-download "Справочник команды: wa bot media download") saves a received file. WhatsApp has no silent message, edit or
  delete for a bot, so those are refused.
* **A bot receives messages by webhook: `bot watch --public-url <tunnel address>`[↗](/llms.mdx/docs/ru/wa/commands-bot/content.md#wa-bot-watch "Справочник команды: wa bot watch").** Meta never lets a client poll,
  so `wa` listens on `127.0.0.1:8766` behind your tunnel, answers Meta's subscription check with the verify token,
  refuses any delivery not signed with your app secret, and acknowledges a delivery only once it is in the local
  store. Keep both with `bot auth set --secret app-secret`[↗](/llms.mdx/docs/ru/wa/commands-bot/content.md#wa-bot-auth-set "Справочник команды: wa bot auth set") and `--secret verify-token`. `bot webhooks set <url>`[↗](/llms.mdx/docs/ru/wa/commands-bot/content.md#wa-bot-webhooks-set "Справочник команды: wa bot webhooks set")
  points this number's webhook at the address. Delivery receipts arrive too. With the store holding a person's last
  message, a free-form send more than 24 hours later is refused before it leaves.
* **`bot mcp`[↗](/llms.mdx/docs/ru/wa/commands-bot/content.md#wa-bot-mcp "Справочник команды: wa bot mcp") serves the bot's commands to an agent**, as tg and max do, and [docs/bot.md](/llms.mdx/docs/ru/wa/bot/content.md) walks through
  Meta's test-number setup, the tunnel and each command.
* **Verified media backups.** `attachments download <dir>`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-attachments-download "Справочник команды: wa attachments download") archives available files across chats with size and
  SHA-256 manifests; `attachments check <dir>`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-attachments-check "Справочник команды: wa attachments check") verifies them offline. `attachments jobs`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-attachments-jobs "Справочник команды: wa attachments jobs") manages opt-in Linux
  daily timers. Completed copies survive interrupted runs and message-store deletion; interrupted files restart.
  `attachments move <dir> <archive-dir> --before-time <time>`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-attachments-move "Справочник команды: wa attachments move") moves older images into another verified archive,
  retaining relocation records so checks follow the copies and later downloads do not duplicate them.
* Saved voice-note transcripts match word forms and spellings that speech recognition may have garbled.
  `text:` searches written text only; `exact:` disables expansion for that word.
* **cli-core 0.394.0.** Store and statistics commands gain examples, and `contacts prepare`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-contacts-prepare "Справочник команды: wa contacts prepare") gives a cited brief before a conversation.
* **Upgrades are checked against saved state from version 0.2.0.** Offline validation uses a synthetic
  profile to check that configuration, stored messages and the device database location survive an upgrade.
* **Pull requests cannot grow the command-lint baseline.** New violations must be fixed or carry a dated,
  reasoned override, so adding a feature cannot silently weaken the existing checks.

### Changed — may break callers [#changed--may-break-callers-2]

* **Shared flags use one meaning.** Analysis uses `--analysis-provider`, vectors `--embedding-provider`, consent removal `--consent-provider`, tag ownership `--claim` and stored-answer removal `--answer-model`. Contact notes read `--text-file`; group message lifetime is `--disappear-after`. Catch-up views use query terms such as `inbox kind:group`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-inbox "Справочник команды: wa inbox"). Old CLI flags remain hidden aliases for one compatibility release and cannot be combined with their replacements; saved MCP requests must use canonical arguments.
* MCP message deletion takes `message`, chat export takes `chat`, and duplicate-task operations take `task`
  and, for a pair, `other_task`. Update saved MCP requests using `messages`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-messages "Справочник команды: wa messages"), `chats`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-chats "Справочник команды: wa chats") or `dup`.
  CLI positional arguments keep their order.
* Command discovery (`commands`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-commands "Справочник команды: wa commands") and `commands schema`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-commands "Справочник команды: wa commands")) rejects `--jsonl`; use `--json` for its single document.
* **Read commands no longer send read receipts.** `messages list`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-messages-list "Справочник команды: wa messages list"), `inbox`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-inbox "Справочник команды: wa inbox") and `review`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-review "Справочник команды: wa review") drop `--mark-read` and
  `--no-mark-read`; remove `catch_up_marks_read` from configuration and use `chats mark-read`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-chats-mark-read "Справочник команды: wa chats mark-read") explicitly.
* **Misspelled permission keys now stop the command.** Correct or unset keys such as `messages.sedn` before running.
* **A mistyped profile lists the real profiles.** An unlinked profile's login hint now points to `setup`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-setup "Справочник команды: wa setup").
* **Setup returns suggested commands in `item.commands` and login details in `item.session`.** Update scripts
  that read `item.next` or `item.device`; `next` is reserved for structured continuation steps.

### Fixed [#fixed-2]

* cli-core 0.399.0 supplies the shared flag migration, additional help examples, offline review and the updated MCP server dependency. The command-lint baseline drops from 52 entries to 38; guides, skill and the generated reference use the released flags.
* Message-search commands no longer list or delete saved meeting searches.
* Command corrections preserve the chosen profile; help shows concise descriptions and concrete examples.
* **More useful command discovery.** cli-core 0.396.0 adds shared examples, concise skill summaries and profile-preserving corrections for joined command paths; cli-base 0.50.2 recognizes the approved messenger vocabulary and flag roles. Command discovery uses `--json` and refuses `--jsonl`.
* **Input errors name the selected command's flags.** WhatsApp adapters report domain fields for unsupported invite-link filtering, conflicting name fields and privacy refusals; cli-core formats those fields at the CLI boundary.
* **CI scans the checked history.** An unrelated fetched branch no longer fails a clean pull request's secret check; findings in the checked commit or any ancestor still block it.
* **A ban's end is shown in the local time zone and names that zone.** Stored timestamps remain UTC.
* **Unexpected engine failures use the provider error code.** Known validation and messenger errors keep their codes.
* **Agents are no longer offered channel comments, which WhatsApp cannot read** (cli-core 0.393.0). A direct call
  fails before connecting. Commands also show more concrete examples in their help.

### Security [#security]

* **The engine uses the patched Go certificate verification library.** Release and monthly checks now
  audit reachable Go vulnerabilities, and dependency updates cover the engine's Go module.
* **Local releases run engine tests, the coverage floor and security checks before publishing.** The npm token
  is supplied only to publishing, and publishing skips lifecycle scripts because validation already built the package.

## 0.4.0 — 22.10.2026 [#040--22102026]

### Changed — may break callers [#changed--may-break-callers-3]

* **A call with no `outcome` may have ended.** Before, a call message with no `outcome` in `provider_metadata` was
  always still ringing. Now a call that ends for a reason `wa` does not know is kept as "Voice call" with no
  `outcome`, so it does not pass as missed or answered. A script that reads a missing `outcome` as "ringing" should
  read the text as well: a ringing call's text starts with "Incoming".

### Fixed [#fixed-3]

* **A call answered or declined on your phone is stored as answered or declined, not missed.** While `serve`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-serve "Справочник команды: wa serve") or
  `watch`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-watch "Справочник команды: wa watch") runs, WhatsApp tells a linked device only that the call was taken or turned down on another device, and
  `wa` read every such end as missed. Now a call you answer on the phone is "Voice call" with `outcome: answered`,
  one you decline is "Declined voice call", and one that rang out or that the caller hung up before you answered is
  "Missed voice call", as the phone shows it. An answered call taken on the phone has no `duration`: this device does
  not hear when it ends, and `wa` no longer stores `0` for it. A call that rang while `serve`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-serve "Справочник команды: wa serve") was not running, and
  whose end the reconnect does not bring, is stored as missed instead of staying "Incoming voice call".

## 0.3.0 — 22.10.2026 [#030--22102026]

### Added [#added-3]

* **Date filters say how they read the date** (cli-core 0.384.0). The JSON answer of a command with a date filter,
  such as `contacts context`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-contacts-context "Справочник команды: wa contacts context"), `contacts timeline`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-contacts "Справочник команды: wa contacts"), `messages sync`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-messages-sync "Справочник команды: wa messages sync"), `chats moderate`[↗](/llms.mdx/docs/ru/wa/commands-admin/content.md#wa-chats-moderate "Справочник команды: wa chats moderate") and `store export`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-store-export "Справочник команды: wa store export"), gives
  `meta.window` with the `since` and `until` it used, in UTC, and `meta.timezone` when a date you typed had no zone
  and was read in the local one.
* **cli-core 0.382.0.** The first run opens the local store as version 28, which adds columns and removes
  nothing.
* **Your messages show whether they were delivered and read.** In a one-to-one chat, a message you sent carries
  `delivery`: `delivered` once it reached the other person's phone, `read` once they opened it. It comes from
  WhatsApp's receipts, which `serve`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-serve "Справочник команды: wa serve"), `watch`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-watch "Справочник команды: wa watch") and any other command keep, and from the history push. It only moves
  forward. A group's messages have none. `watch --events`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-watch "Справочник команды: wa watch") prints each receipt. Needs cli-core 0.382.0 (store version
  27\). The engine speaks protocol 44.
* **A chat's mute, archive and unread mark from the phone are kept** (cli-core 0.382.0). While `serve`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-serve "Справочник команды: wa serve") or `watch`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-watch "Справочник команды: wa watch")
  runs, and from the history push, the local store saves whether a chat is archived, muted and until when, and
  marked unread. So `inbox`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-inbox "Справочник команды: wa inbox") and `review`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-review "Справочник команды: wa review") over the store leave out muted and archived chats, and `inbox`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-inbox "Справочник команды: wa inbox") lists a chat
  you marked unread. A chat read on the phone loses its unread mark, and the store now counts each new message from
  someone else after that read, so `inbox`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-inbox "Справочник команды: wa inbox") shows a chat again once a new message arrives. `chats show`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-chats-show "Справочник команды: wa chats show") shows
  `muted_until` and `marked_unread`. What to watch for: a read on the phone resets the chat's last-message time to the
  newest message the phone read. Engine wire change: `mutedUntil` and `markedUnread` on a chat. Engine protocol 45.
* **Calls to you are kept as messages, so `inbox`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-inbox "Справочник команды: wa inbox") and `review`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-review "Справочник команды: wa review") show who called.** While `serve`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-serve "Справочник команды: wa serve") or `watch`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-watch "Справочник команды: wa watch") runs, a
  call becomes a message in the caller's chat: "Incoming voice call" as it rings, then "Missed voice call", "Declined
  voice call" or "Voice call" when it ends. It carries `"action": "call"` in `provider_metadata`, as tg marks its calls,
  so chat stats do not count it as something said. A group call is kept as it rings. `wa` never answers or declines a
  call. The engine speaks protocol 42.

### Fixed [#fixed-4]

* **A store the pre-rename `cli-messaging` wrote is refused again, and left untouched** (cli-core 0.385.0). Since
  cli-core 0.382.0 such a file was opened and failed with `internal_error`; it now fails with `configuration_error`.
* **`chats list`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-chats-list "Справочник команды: wa chats list") shows the groups you are in.** WhatsApp has no chat list, so the store knew only the groups a
  history push or a message had named, and `chats list kind:group`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-chats-list "Справочник команды: wa chats list") could come back empty. Every connection now saves
  the groups you are in, with their names and member counts; run `serve`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-serve "Справочник команды: wa serve") (or any command that connects) once for
  them to appear.
* **A chat is found by a name copied with its emoji, by part of its name and whatever the case.** "Семья❤️" copied
  from WhatsApp carries an invisible mark after the heart, and was refused as "no chat by that name or id" while
  "Семья❤" worked. Names now match without that mark, ignoring case, and by part of the name, as `wa` already finds
  a person (cli-core 0.381.0). A name that matches several chats is refused as before; the refusal now reads "N chats
  match that name". What to watch for: a part of a name that used to be refused may now name a chat, when exactly
  one chat matches it.
* **Reactions that other people send are stored** (cli-core 0.381.0). `serve`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-serve "Справочник команды: wa serve") and `watch`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-watch "Справочник команды: wa watch") keep each
  person's newest reaction, live and from the history push, and `watch --events`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-watch "Справочник команды: wa watch") passes each one on as a
  `person_reaction` event. A message then shows its reaction counts and your own reaction, from the phone, in
  `reactions`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-reactions "Справочник команды: wa reactions"). A reaction taken back is dropped, and an older history push no longer undoes a newer change. What to
  watch for: a reaction you send with `reactions add`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-reactions-add "Справочник команды: wa reactions add") still goes to WhatsApp only, not to the store. Engine wire
  change: a `reaction` event and a history push's `reactions`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-reactions "Справочник команды: wa reactions"). Engine protocol 43.
* **`stats chats retention`[↗](/llms.mdx/docs/ru/wa/commands-admin/content.md#wa-stats-chats-retention "Справочник команды: wa stats chats retention") and `chats stats show`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-chats "Справочник команды: wa chats") read `--since-time`/`--until-time` in their `--timezone`**, and a
  date alone in retention's `--until-time` covers that whole local day (cli-core 0.380.0). `stats charts`[↗](/llms.mdx/docs/ru/wa/commands-admin/content.md#wa-stats-charts "Справочник команды: wa stats charts"), `contacts
  timeline`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-contacts "Справочник команды: wa contacts") and the MCP `stats`[↗](/llms.mdx/docs/ru/wa/commands-admin/content.md#wa-stats "Справочник команды: wa stats") tool name the zone in `meta.timezone` and give the UTC window in `meta.window`.
* **A chat you read on the phone stops counting as unread.** While `serve`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-serve "Справочник команды: wa serve") or `watch`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-watch "Справочник команды: wa watch") runs, reading a chat on the
  phone sets its unread count in the local store to 0, so `inbox`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-inbox "Справочник команды: wa inbox") no longer shows it. Before, the count stayed until
  the next history push. What to watch for: new messages do not raise a stored count, here or in any other chat, so
  until the next history push `inbox`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-inbox "Справочник команды: wa inbox") finds them only with `--new`. Archiving, muting, pinning, marking a chat unread,
  deleting or clearing a chat on the phone are not saved yet, so `inbox`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-inbox "Справочник команды: wa inbox") still lists an archived or muted chat.
  `watch --events`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-watch "Справочник команды: wa watch") prints none of these changes, as in `tg`.
* **The ban error says its end time is in UTC.** "the ban ends 2026-10-21T14:03:00.000Z" now ends in "UTC", so it is
  not read as local time. `standing.until` is unchanged.

### Changed — may break callers [#changed--may-break-callers-4]

* **A typed date or time is read in your zone, and a date alone covers your whole local day** (cli-core 0.379.0).
  `--since-time 2026-10-01` used to start at UTC midnight; it now starts at local midnight, and `--until-time` with a
  date alone ends at the end of that local day. A time without an offset, such as `chats mute --until
  2026-10-09T09:00`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-chats-mute "Справочник команды: wa chats mute"), is read in the command's `--timezone` where it has one, else in the computer's zone. A value
  with `Z` or an offset means what it says, as before. What to watch for: a script that passed a date alone and
  expected the UTC day now gets the local one; pass `2026-10-01T00:00:00Z` to keep the old window. Stored and printed times stay
  UTC.

## 0.2.0 — 21.10.2026 [#020--21102026]

### Changed — may break callers [#changed--may-break-callers-5]

* **`--qr-file` is gone: without a terminal, `session start`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-session-start "Справочник команды: wa session start") and `setup`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-setup "Справочник команды: wa setup") print the QR code as text** for an agent to
  paste into the chat, instead of a PNG the person opens in an image viewer. The text is plain half blocks, no
  colours, about 73 columns wide. Each code is followed by a note telling an agent to paste it, and with `--json` it is
  also one stderr line, `{"event":"qr","qr":{"text","expires_at","scan"}}`. A QR link no longer needs a terminal; a
  pairing-code link (`phone`) still does, and without one says that it asks questions. A script that passed
  `--qr-file` now fails with an unknown option. In a terminal the code is drawn as before, as in tg and max.
* **A one-to-one chat typed by its phone number is addressed by its LID**, the id WhatsApp files that chat under,
  when WhatsApp has already given it. WhatsApp answers a send by the number with the LID, so a later
  `messages delete`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-messages-delete "Справочник команды: wa messages delete"), `messages star`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-messages-star "Справочник команды: wa messages star"), `reactions add`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-reactions-add "Справочник команды: wa reactions add") or `polls vote`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-polls-vote "Справочник команды: wa polls vote") by the number could miss the message: the
  deleted text stayed searchable, the star was lost, and the vote made a second chat. Every command that names a chat now looks the
  number up in the LIDs this device knows; nothing is asked of WhatsApp and nothing is recorded. A number with no
  known LID, a group, a LID or a channel is used as typed. An `--offline` command reads the store by the id as typed,
  and finds a chat that moved from that number to its LID once the store recorded the move (see Added).
  Engine wire change: a `canonicalChat` request. Engine protocol 38. Two things the owner may notice:
  * A recipient list entry added by the phone number stops matching once that number has a LID, and a send to it
    is refused with exit 7. The refusal names the id to allow: run `recipients add`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-recipients-add "Справочник команды: wa recipients add") with it, or with the number
    again, which now saves the LID. An entry added by the number moves to the LID by itself at the next `serve`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-serve "Справочник команды: wa serve") or
    `watch`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-watch "Справочник команды: wa watch") start, when this device already knows the number's LID, whether or not the store holds a chat under it
    (cli-core 0.356.0). The number is not asked of WhatsApp and is not recorded. Engine wire change: `recipients`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-recipients "Справочник команды: wa recipients") on
    the `storedChats` request. Engine protocol 40.
  * A chat the store already holds under the phone number, such as one wa 0.1.0 saved, moves to its LID on the spot
    (cli-core 0.356.0): the first command that names it by the number, a send, `delete`, `star` or reaction
    included, moves the stored chat, its messages and its recipient-list entry to the LID, then acts on the LID
    chat. An `--offline` command moves nothing; it finds such a chat by the number once the store recorded the move.
* **`wa --help` and a bare `wa` show a short first screen** instead of every command and option: what `wa` is for,
  the usage line, the other WireCat tools it works with, and where to start. `wa --help-all` prints the old help and `wa help options` the
  options of every command. Each command's own `--help` now ends with what it returns, the commands that usually
  come next, and an example. A bare `wa commands`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-commands "Справочник команды: wa commands") prints a text list by section, also when piped; a script that read
  its JSON must pass `--json` (cli-core 0.344.0).
* **`chats mark-read`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-chats-mark-read "Справочник команды: wa chats mark-read") takes a mark-unread off, and needs WhatsApp's settings keys for it.** It sent a read receipt
  only, which leaves a chat marked unread on the phone, and in your own chat it sent nothing at all. It now first
  marks the chat read on your devices, up to `--until-id` or the newest message the store holds, then sends the
  receipt as before. The same goes for `--mark-read` on `messages list`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-messages-list "Справочник команды: wa messages list"), `inbox`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-inbox "Справочник команды: wa inbox") and `review`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-review "Справочник команды: wa review"), one more write per
  chat. Right after linking, before WhatsApp has sent the settings keys, these now fail with
  `settings.keys-missing` (safe to retry) and send no receipt, where they used to send it; keep `serve`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-serve "Справочник команды: wa serve") running a few
  minutes and run them again. Engine protocol 34.
* **The MCP server's `wa_read` and `wa_write` take each command's own arguments, in snake_case.** `search messages`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-search-messages "Справочник команды: wa search messages")
  takes `query` (not `text`) and no `ast`; `polls create`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-polls-create "Справочник команды: wa polls create") takes `question`; `wa_tools_search` shows each command's
  fields. The agent is offered every command the profile's permissions allow, including some it was not offered
  before; marking read, `--as-owner` and `--allow-any-file` stay off MCP. An agent's runs are named `mcp <command>`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-mcp "Справочник команды: wa mcp")
  in run history and the send journal. `conversations rebuild`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-conversations-rebuild "Справочник команды: wa conversations rebuild") replaces the agent-only `conversations_refresh`.
* **A global `npm install` no longer writes the agent skill into `~/.claude/skills` and `~/.agents/skills` on its
  own.** npm hides what an install script prints, so the files appeared without a word. `wa personal setup` still
  offers the skill, and `wa skill install`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-skill-install "Справочник команды: wa skill install") installs it; set `WA_INSTALL_AGENT` (`all`, `claude`, `codex`, `cursor` or
  `gemini`) to have the install do it as before. The Windows installer is unchanged: it says what it installs.
* **`session start phone`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-session-start "Справочник команды: wa session start") and `setup --method phone`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-setup "Справочник команды: wa setup") refuse a number without `+` and the country code** (exit 2,
  `input.invalid`). WhatsApp reads the first digits of the number as the country code, so a number typed the way it
  is dialled at home asked for a pairing code on someone else's account. Nothing reaches WhatsApp until the number
  starts with `+`.
* **`messages delete`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-messages-delete "Справочник команды: wa messages delete") without `--for-everyone` deletes the message for you only, where it used to be refused** (exit
  2\). `wa` asks WhatsApp to take the messages from this account's devices, to leave them with the
  others in the chat, and to keep the photos and files the phone saved from them. Each message must be in the local
  store, since WhatsApp names it by its sender and the time it was sent; one the store lacks is exit 6 and nothing is
  deleted. A device without WhatsApp's settings keys yet answers `settings.keys-missing`, as `chats mute`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-chats-mute "Справочник команды: wa chats mute") does. An
  agent's `messages delete`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-messages-delete "Справочник команды: wa messages delete") over MCP, which was refused too, now does the same, for the owner only; deleting for
  everyone stays the owner's `--for-everyone`. A deletion asks first by default, and over MCP that level lets the
  agent's call through, so at the default an agent can now delete the owner's copy. To keep agents from it, set
  `permissions.messages.delete` to `readonly` or `deny`: the MCP server then does not offer the command, and an
  agent's call is refused with `permission_error` (`access.denied`), as the owner's own `messages delete`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-messages-delete "Справочник команды: wa messages delete") at those
  levels is, with exit 5. A delete
  of several messages that fails partway, with or without `--for-everyone`, now names the ones already deleted and
  is not marked safe to retry: delete only the rest. A message you delete for yourself on the phone leaves the
  local store the same way while `serve`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-serve "Справочник команды: wa serve") or `watch`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-watch "Справочник команды: wa watch") runs. Checked live on the phone for your own message in your
  own chat; a message in a group or in a one-to-one chat with someone else, and a delete made on the phone, are not
  checked yet.
* **`messages download`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-messages-download "Справочник команды: wa messages download") asks your phone for a file WhatsApp no longer keeps**, as WhatsApp's apps do, instead of
  answering `not_found` (exit 6) at once. It waits up to 20 seconds for the phone to upload it again and fetches the
  new copy. A phone that does not answer ends the download with `timeout` (exit 9); exit 6 now means the phone no
  longer has the file either. A script that read exit 6 as "expired" must also expect exit 9, and give a slow phone a
  longer `--timeout`. A new copy that then fails to download is `provider_error` (exit 11, `media.retry-failed`),
  whatever the first failure's code was; when the phone answered an error but still gave a path, it is the phone's
  answer instead (see Fixed). The store keeps the new copy's address, so a later download or forward
  uses it and does not ask the phone again (see Fixed).
  **Known limitation: a file WhatsApp no longer keeps does not download yet.** On the phones tried, the phone answers
  that it uploaded the file again, but it encrypts the new copy with a new key that it does not send to linked
  devices, so `wa` cannot read it. The download then ends with `media.retry-failed` ("the phone uploaded this file
  again, but the new copy did not download") and saves nothing, rather than a broken file. A file WhatsApp still
  keeps downloads as before. For an old file, open it on the phone, or ask the sender to send it again.
* **`messages forward`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-messages-forward "Справочник команды: wa messages forward") sends a stored place or contact card, where it used to refuse it.** The store now keeps a
  place's coordinates, name and address, and a contact card itself, next to a file's keys, where no answer shows
  them. A place or card stored before this, a live location and several cards in one message are still refused.
* **A person's chat moves to their LID when WhatsApp gives them one.** WhatsApp names a one-to-one chat by the
  person's phone number until it gives them a LID, its private id for a person. `serve`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-serve "Справочник команды: wa serve") and `watch`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-watch "Справочник команды: wa watch") now move the
  stored chat and its messages to the LID, so `messages list`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-messages-list "Справочник команды: wa messages list") and `search`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-search "Справочник команды: wa search") show one chat, and no chat is left under
  the phone-number id (`…@s.whatsapp.net`). A script that saved that id must take the new one from `chats list`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-chats-list "Справочник команды: wa chats list"). The
  move is repeated at each start for 30 days, so one that came while only a one-shot command ran still lands. A
  send typed to the old id stores a chat under it again, which a later repeat of the move merges. The merged chat
  keeps the stricter privacy of its two forms: hidden from search if either was, personal if they disagree, and a
  scope pinned on either stays pinned (cli-core 0.353.0). A chat stored under a phone number by wa 0.1.0 moves too:
  `serve`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-serve "Справочник команды: wa serve") and `watch`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-watch "Справочник команды: wa watch") hand the stored chat ids to the engine as they start, and one whose LID WhatsApp already gave
  moves at once (cli-core 0.350.0, `storedChats`). If that fails, `wa` says so once on stderr (`stored_chats_failed`
  in the run record) and goes on. Engine wire change: a `storedChats` request. Engine protocol 37.
* **`serve`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-serve "Справочник команды: wa serve") asks WhatsApp for the LID of a chat still in phone form**, so that chat moves too. It asks a minute after
  history stops coming or `serve`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-serve "Справочник команды: wa serve") or `watch`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-watch "Справочник команды: wa watch") starts, for chats the account already has only: five people per
  request, one request every 10 seconds, at most 20 people per run, and each person at most once a week. The owner's
  own `lookup` keeps its own pace. If WhatsApp asks to slow down, the lookups stop for a week and the next write is
  refused with `account.rate-limited`, which holds the profile's writes for 15 minutes, also when `serve`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-serve "Справочник команды: wa serve") restarts
  meanwhile. Not yet run against WhatsApp.
* **A command cut off by a dropped or ended connection no longer answers `network_error`** (exit 10), which invited
  a retry and a double send. A send, edit, reaction, group change or other write whose request left before the
  network dropped, and could not be sent again, now answers `outcome_unknown`: exit 14, `retry.safe: false`, also
  when WhatsApp handed the login to another connection meanwhile, since the write may have gone through. Check the
  chat before you send again. Otherwise, a command relayed through `serve`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-serve "Справочник команды: wa serve") while another process took the login over
  now answers `device.replaced`, and after a ban or a logout `account.banned` or `device.logged-out`. A script that
  retried on `network_error` must not retry these.
* **`chats rules set`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-chats-rules-set "Справочник команды: wa chats rules set") refuses a `newAccount` rule** with `validation_error` (exit 2) and saves nothing: WhatsApp does
  not say when an account was made, so the rule was saved and could never match. A script that sets one must drop it.
* **A send that waits on another `wa` process exits 9, not 1** (cli-core 0.338.0): when another process on the
  profile is sending or clearing the pace for longer than the 5 s wait, a send or `flood clear`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-flood-clear "Справочник команды: wa flood clear") answers `timeout`,
  since nothing was sent and a retry is safe. A change to the recipient list held elsewhere for 5 s is
  refused with exit 9 and the list stays as it was; two changes at once no longer undo each other.
* **`wa upgrade --offline`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-upgrade "Справочник команды: wa upgrade") exits 2** instead of asking npm anyway.
* **`WA_READ_ONLY` refuses more, always with exit 5 and "this process is read-only (WA_READ_ONLY)"** (cli-core
  0.328.0 to 0.337.0). An agent that did any of these under the lock must do it in a process without
  it. Newly refused:

  * `session start`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-session-start "Справочник команды: wa session start"), `session end`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-session-end "Справочник команды: wa session end") and `setup`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-setup "Справочник команды: wa setup"), before they act ("it cannot log in or out"); `session start`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-session-start "Справочник команды: wa session start") and
    `setup`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-setup "Справочник команды: wa setup") on a profile linked before used to go ahead;
  * the message store: `store reset`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-store-reset "Справочник команды: wa store reset"), `restore`, `clear`, `migrate`, `repair`, `decrypt` and `copies delete`
    (`--dry-run` still previews);
  * what the owner saved: `searches create|delete|clear`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-searches "Справочник команды: wa searches"), `contacts alias set|rm`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-contacts "Справочник команды: wa contacts"), `contacts notes
    add|edit|remove`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-contacts-notes "Справочник команды: wa contacts notes") and `tags remove`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-tags-remove "Справочник команды: wa tags remove");
  * other local writes: `tags add`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-tags-add "Справочник команды: wa tags add"), `tags auto`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-tags "Справочник команды: wa tags"), `mentions confirm|reject`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-mentions "Справочник команды: wa mentions"), `contacts link|unlink`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-contacts "Справочник команды: wa contacts"), `attachments text
    set`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-attachments "Справочник команды: wa attachments"), `chats tracking add|remove`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-chats-tracking "Справочник команды: wa chats tracking"), `conversations links add|clear`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-conversations-links "Справочник команды: wa conversations links"), `conversations consents revoke`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-conversations-consents "Справочник команды: wa conversations consents") and `tasks
    reject`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-tasks-reject "Справочник команды: wa tasks reject"); `tasks close`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-tasks-close "Справочник команды: wa tasks close") only suggests the close;
  * and their MCP tools.

  `messages delete`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-messages-delete "Справочник команды: wa messages delete") under the lock exits 5, not 7 ("asks before it acts"). `wa upgrade --check`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-upgrade "Справочник команды: wa upgrade") now runs under the
  lock; `wa upgrade`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-upgrade "Справочник команды: wa upgrade") without it is still refused.
* **`conversations embed`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-conversations-embed "Справочник команды: wa conversations embed") and `conversations build`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-conversations "Справочник команды: wa conversations") count as writes to an outside service, and `search
  conversations`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-search-conversations "Справочник команды: wa search conversations") as a read from one** (cli-core 0.334.0, 0.336.0): a failed run is not marked safe to
  retry, and under `WA_READ_ONLY` each refuses before it sends chat text or the query to a remote provider; a local
  model still works. They always run in the calling process, never through `serve`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-serve "Справочник команды: wa serve"). Their help now says "Changes
  something in WhatsApp", which here means the outside provider.
* **A ban or rate limit holds every write, for as long as it lasts** (cli-core 0.334.0): while WhatsApp has the
  account banned or rate-limited, a reaction, `chats mark-read`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-chats-mark-read "Справочник команды: wa chats mark-read") and a group title change are refused with exit `5`
  too, not only sends and edits. Reads still work; `inbox`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-inbox "Справочник команды: wa inbox") and `review`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-review "Справочник команды: wa review") with `--mark-read` still show what they read
  and warn that nothing was marked read. A temporary ban WhatsApp dates holds writes until its end, the error says
  when, and `standing.until` is that time. A ban with no end has `standing.state` `banned`, not `frozen`, and
  `until: null` in `doctor --json`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-doctor "Справочник команды: wa doctor"), `flood clear --json`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-flood-clear "Справочник команды: wa flood clear") and `server status --json`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-server-status "Справочник команды: wa server status"), where it held for a year
  before; `wa <profile> flood clear` or a `doctor --online`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-doctor "Справочник команды: wa doctor") that connects lifts it.
* **`serve`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-serve "Справочник команды: wa serve") banned by WhatsApp is not restarted by its unit** (exit 5 joins exit 4 in the unit's no-restart list):
  a restart 30 s later connected again during the ban. `wa <profile> server status` says it stopped and will not
  restart; start it again with `wa <profile> server start` once the ban ends.
* **An older client's `session end`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-session-end "Справочник команды: wa session end") relayed into `serve`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-serve "Справочник команды: wa serve") is refused** with `permission_error`, exit
  `5`, `sent: false`, naming `server stop`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-server-stop "Справочник команды: wa server stop"); it was `provider_unavailable`, exit `12`, `device.in-use`. `serve`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-serve "Справочник команды: wa serve")'s
  connection and the keys stay as they were.
* **Ctrl+C or `--timeout` during the history wait after linking ends the wait, not the command**: `session start`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-session-start "Справочник команды: wa session start")
  keeps what arrived, counts it and exits 0. It exited 130 or 9, though the device was linked. `setup`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-setup "Справочник команды: wa setup") goes on to
  its account, chat and agent steps, which get a deadline of their own (cli-core 0.334.0); a
  Ctrl+C after the wait ends setup (130). With `--timeout`, the link and the wait share that one deadline, and the
  steps after it get that long again.
* **`chats list`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-chats-list "Справочник команды: wa chats list") and `chats show`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-chats-show "Справочник команды: wa chats show") answer from the local store and never connect** (cli-core 0.328.0), so they run
  here while `serve`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-serve "Справочник команды: wa serve") runs. `recipients add`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-recipients-add "Справочник команды: wa recipients add") runs through `serve`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-serve "Справочник команды: wa serve") instead of being refused with exit 12.
* **A link without a terminal waits 5 minutes by default, not 30 seconds** (cli-core 0.328.0), so an agent's
  `session start`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-session-start "Справочник команды: wa session start") is not cut off before the code is scanned. `--timeout` still decides when given.
* **A command path given as one argument fails** (cli-core 0.328.0): `wa 'chats list'` printed the root help and
  exited 0; it now fails with `validation_error`.
* **`wa mcp`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-mcp "Справочник команды: wa mcp") offers only what `wa` has** (cli-core 0.328.0, 0.335.0): `chats link create`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-chats "Справочник команды: wa chats"), which failed, is gone,
  and a command that refuses `--offline` no longer has an `offline` input; an agent that passes one gets
  `validation_error`. `metadata get`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-metadata "Справочник команды: wa metadata") and `metadata refresh`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-metadata "Справочник команды: wa metadata"), which failed too, now work (see Added).
* **`chats events`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-chats-events "Справочник команды: wa chats events") answers from the local store** (cli-core 0.336.0): it no longer refuses with exit `2`, never
  connects, and works with `--offline`. What it lists, and how `stats chats show`[↗](/llms.mdx/docs/ru/wa/commands-admin/content.md#wa-stats-chats-show "Справочник команды: wa stats chats show") counts members from it, is under
  Added.
* **A chat or person named by name is found in the local store first** (cli-core 0.337.0): part of the name is
  enough, and a name several stored chats match is refused with "… matches N chats", as `chats show`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-chats-show "Справочник команды: wa chats show") refuses it; a
  caller that matched the old "N chats share that name" must match the new text. Only a name the store does not hold
  is asked of WhatsApp's chat list, so a one-shot command now finds a stored group by its name. `watch`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-watch "Справочник команды: wa watch") titles a
  chat from the store and follows its renames; a chat the store has never held has no title in `watch`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-watch "Справочник команды: wa watch").
* **A live edit or deletion of a channel post is no longer passed on**: `watch`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-watch "Справочник команды: wa watch") and `serve`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-serve "Справочник команды: wa serve") used to hand it on under
  an id the store does not file the post by. A channel's posts are now read with `messages sync <channel>`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-messages-sync "Справочник команды: wa messages sync").

### Security [#security-1]

* **The engine log (`WA_ENGINE_LOG`) no longer keeps media download links.** When a download failed on the network,
  whatsmeow wrote the whole link into the log: the file's path on WhatsApp's servers, its hash and the signed
  `oh`/`oe` values, which together fetch the file for anyone who has them; a failed delete of history-sync media wrote
  the media `auth` token the same way. Every link now becomes `[url]`, a server path `[path]`, and those values `…`,
  before the line is written.
* **A message sent to a phone number is saved in the chat WhatsApp answered, with that chat's privacy kept**
  (cli-core 0.356.0). `wa` answers a send to a person who has a LID with their LID chat, but the message was saved
  under the number that was typed, in a second chat. Now `messages send`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-messages-send "Справочник команды: wa messages send"), `polls create`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-polls-create "Справочник команды: wa polls create") and `messages forward`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-messages-forward "Справочник команды: wa messages forward") save
  it in the answered chat. A chat made for it takes the typed chat's search visibility and scope; a chat that exists
  already keeps the stricter of the two, so a chat hidden from search does not come back into search under its other
  id. `wa <profile> sends list` names the answered chat beside the typed one when they differ.
* **A failed background `messages sync`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-messages-sync "Справочник команды: wa messages sync") no longer writes a chat title or a name into its job file** (cli-core
  0.355.0). The file keeps the error's code and points at `wa store jobs show <id>`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-store-jobs-show "Справочник команды: wa store jobs show"), which prints the path of the
  job's log. The full message stays in that log, which only you can read (mode `0600`).
* **A chat hidden from search no longer turns up in a search that does not name it** (cli-core 0.353.0). The
  messages by and about a person in `contacts context`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-contacts-context "Справочник команды: wa contacts context"), the pictures lane of `search messages`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-search-messages "Справочник команды: wa search messages"), and the meaning half
  of `search conversations`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-search-conversations "Справочник команды: wa search conversations") and `conversations related`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-conversations-related "Справочник команды: wa conversations related") left it in, and the search answers listed it as not yet
  embedded. A sender-only lookup no longer counts its messages. `wa` has no command that hides a chat from search,
  so only a store edited by hand was affected.
* **`WA_READ_ONLY` refuses a write to WhatsApp before anything connects.** `messages send`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-messages-send "Справочник команды: wa messages send"), `edit`, `delete`,
  `reactions add`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-reactions-add "Справочник команды: wa reactions add") and the other commands that change something on WhatsApp used to connect and find the chat first;
  now they exit 5 at once, and a broken login no longer turns the refusal into a network failure. A permission level
  of `readonly` or `deny` on the command does the same (cli-core 0.343.0).

### Fixed [#fixed-5]

* **An album wa sends shows on the phone as one album.** It showed as two messages, a photo and a video. Messages
  wa sends now carry a message secret and a reporting token (all but reactions and poll votes), as WhatsApp Web,
  Baileys and mautrix-whatsapp send them, and each file of an album points at the album by the chat id WhatsApp
  delivered it to (the LID when the chat was typed by its phone number). Checked on a phone.
* **Photos and videos wa sends show on the phone.** They never did, as an album or a forward either, while wa's own
  linked devices received them: the message lacked the file's URL. Photos, videos, voice notes, documents and
  stickers now carry it, as WhatsApp's own apps and mautrix-whatsapp send them. Checked on a phone. A message now
  also carries the time its file's key was made, as Baileys sends it, and a document with a caption goes in the
  wrapper WhatsApp's apps use. A file stored before this fix, or one the phone uploaded again, gets a URL built from
  its path when it is forwarded. The URL is kept with the file's keys in the store and is never printed. Engine wire
  change: `url` and `mediaKeyTimestamp` in a file's ref. Engine protocol 41.
* **A chat id works in a query without quotes.** `chat:100000000000002@lid` and `chat:120363000000000001@g.us`
  failed with `query.unsupported-operator`, because the `@` was read as an operator; only the quoted form worked.
  Both forms work now (cli-core 0.375.0, cli-base 0.47.3).
* **`session end`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-session-end "Справочник команды: wa session end") unlinks the device on WhatsApp's side, which it never did before.** Since the first release the
  engine sent the logout without connecting, so every `session end`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-session-end "Справочник команды: wa session end") stopped with "the connection to WhatsApp broke
  before it confirmed the change; it may have gone through — check first", sent nothing and kept the keys. If you
  deleted a profile's keys by hand after that, the device is still linked: remove it on the phone, in WhatsApp →
  Linked devices. `session end`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-session-end "Справочник команды: wa session end") now connects first, then logs out. When WhatsApp refuses the device on connect (logged
  out, or removed on the phone), the keys here are deleted, the command exits 0 and says "WhatsApp had already dropped
  this device". A network failure before the logout is sent keeps the keys; a connection cut after it was sent still
  answers "may have gone through". No engine wire change.
* **A group the owner left is found by its name or any id when a command reads its kept history** (cli-core
  0.368.0): `store export`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-store-export "Справочник команды: wa store export") (also `--output-dir` with named chats), `store status`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-store-status "Справочник команды: wa store status"), `messages context --thread`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-messages-context "Справочник команды: wa messages context"),
  `messages evidence`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-messages-evidence "Справочник команды: wa messages evidence"), a search's `--chat` and `chat:`, `metadata get`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-metadata "Справочник команды: wa metadata"), `chats members`[↗](/llms.mdx/docs/ru/wa/commands-admin/content.md#wa-chats-members "Справочник команды: wa chats members"), `chats events`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-chats-events "Справочник команды: wa chats events"),
  `chats documents`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-chats-documents "Справочник команды: wa chats documents"), stats, tags, tasks, conversations, embeddings, pictures and attachments, as `chats show`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-chats-show "Справочник команды: wa chats show") and
  `messages list`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-messages-list "Справочник команды: wa messages list") already did. Before, these refused a left group by every name and id. `chats tracking add`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-chats-tracking-add "Справочник команды: wa chats tracking add") and
  `store gaps plan`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-store-gaps "Справочник команды: wa store gaps") still refuse it.
* **More of `serve`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-serve "Справочник команды: wa serve")'s warnings carry a code in its log**, so a script can match the code instead of the sentence: a
  flood wait (`flood_wait`) or a long pace wait (`pace_wait`), both with `counts.seconds`, a held account
  (`account_frozen`, `account_limited`, `account_banned`), a wait that could not be remembered
  (`wait_not_remembered`), a send missing from the send journal (`send_not_journaled`), a recipient list that could
  not be re-keyed or read, and the reply audience and template warnings. The log record holds no sentence, chat id or
  name; the sentence at a terminal is unchanged (cli-core 0.364.0).
* **The first `serve`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-serve "Справочник команды: wa serve") after an upgrade hands its chat re-keys to the store together**, up to 500 at a time, instead
  of one at a time. On an account with thousands of chats stored by phone number, that start announces a re-key for
  each, and every one was saved as a batch of its own. A re-key that arrives alone waits at most 0.1 s. The store
  saves them in short passes with a pause after each, so another `wa` command run during that start no longer waits
  seconds for it; re-keys left when `serve`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-serve "Справочник команды: wa serve") stops are one warning, and the next `serve`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-serve "Справочник команды: wa serve") applies them (cli-core 0.359.0).
* **A group you left, were removed from, or that was deleted is marked left in the store**, so
  `wa <profile> store clear --left` finds it; until now it found nothing. The mark comes from WhatsApp's group
  notice while `serve`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-serve "Справочник команды: wa serve") or `watch`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-watch "Справочник команды: wa watch") runs, and from a `wa <profile> chats leave` that succeeds; a `chats join`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-chats-join "Справочник команды: wa chats join") that gets
  in takes it off (cli-core 0.356.0), and so does WhatsApp's notice that someone added you back (cli-core 0.357.0);
  a group you had archived stays archived. A group left while nothing was connected is not marked. A group marked
  left drops out of `chats list`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-chats-list "Справочник команды: wa chats list"); `chats show`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-chats-show "Справочник команды: wa chats show") shows it and says you left it, and its messages stay in the store and
  in search until you clear it.
  Engine wire change: `membershipState` on a pushed chat, `"left"` (protocol 39) and `"member"` (protocol 40).
* **`setup`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-setup "Справочник команды: wa setup")'s link step is headed "Link this device"** and no longer asks you to scan a QR code before one is
  drawn. The line under the code says where to scan; a narrow terminal shows only the hint to widen it.
* **A terminal too narrow for the QR code no longer asks you to scan it** (cli-core 0.350.0). `session start`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-session-start "Справочник команды: wa session start") and
  `setup`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-setup "Справочник команды: wa setup") said where to scan in WhatsApp before the code; when the code did not fit, only the hint to widen the
  terminal followed. Now the scan line comes after the drawn code, and a narrow terminal shows only the hint.
* **A one-shot command now saves the history WhatsApp pushes to it.** WhatsApp sends a history push to a linked
  device once. A command such as `messages send`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-messages-send "Справочник команды: wa messages send") with no `serve`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-serve "Справочник команды: wa serve") running received it and dropped it. It is now saved
  to the store like the messages queued for it, and the command waits up to 3 seconds at exit for a push still
  downloading (cli-core 0.348.0, `listenHistory`). `session end`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-session-end "Справочник команды: wa session end") ends this quietly; when the phone logs the device out
  mid-command, `wa` says on stderr that history batches arriving were not saved.
* **A group taken out of its WhatsApp community no longer names it in the store.** `wa` saves WhatsApp's notice that
  a group left its community, or that the community was deleted, and clears the group's `parent_chat_id`; its title,
  unread count, member count and last activity stay. Each followed channel's push at connect, and any chat whose
  source does not say, no longer erases a stored unread count and last activity either (cli-core 0.348.0). Engine
  wire change: `unread` and `lastMessageAt` may be absent, and `name` and `participants` too, on that notice. Engine
  protocol 36.
* **A group added to a WhatsApp community names it in the store at once.** `wa` saves WhatsApp's notice that a group
  joined a community and sets the group's `parent_chat_id`, keeping its title, counts and last activity. Before, the
  parent showed only after a live read of that one group.
* **`session start`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-session-start "Справочник команды: wa session start") no longer gives up right after the phone confirms the link.** WhatsApp restarts the connection
  once pairing is done, and wa took the start of that restart for a failure: it said "linked, but could not reconnect
  to WhatsApp in time" and exited 10, the device linked but the history never received, while the phone's linking
  screen hung waiting for it. wa now waits for the new connection, up to a minute, and then receives the history as
  before. Both the QR code and the pairing code went this way. If that new connection fails, wa connects once more
  itself a few seconds later, within the same minute, instead of waiting the minute out. Every other command's wait
  for its connection uses the same loop now, so it no longer spins while the old connection is being closed. When the
  phone has pushed nothing after 20 seconds, `session start`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-session-start "Справочник команды: wa session start") says once that it is still waiting, so the pause does not
  look like a hang.
* **A pushed community no longer loses its mark.** The store replaced a chat's `provider_metadata` whole on every
  push, so a later push that did not say a group was a community took `community: true` off it. A key a push leaves
  out now keeps its stored value, and so does a group's `parent_chat_id` (cli-core 0.346.0). Engine protocol
  35\.
* **`inbox`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-inbox "Справочник команды: wa inbox") and `review`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-review "Справочник команды: wa review") check `--json=<fields>` against the message summary's fields**, and refuse a name it does
  not have instead of printing empty items. `--brief` and `--full` no longer mention mail (cli-core 0.345.0).
* **`session start`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-session-start "Справочник команды: wa session start") and `setup`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-setup "Справочник команды: wa setup") link a new profile.** They failed before showing a code with "cannot open the lock
  beside the device store": nothing made the profile's own folder before the engine opened its lock there. The engine
  now makes it, mode 700, before it takes the lock.
* **One pushed event that `wa` cannot handle no longer stops the ones after it.** `serve`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-serve "Справочник команды: wa serve") and `watch`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-watch "Справочник команды: wa watch") handle what
  WhatsApp pushes one event at a time, in order. A history push or a live message whose handling failed used to stop
  the queue, so no later history reached the local store until `wa` restarted. Now that event is skipped, a warning
  on stderr names its kind and error code (never its content), the next event goes on, and when `wa` stops listening it
  says how many were skipped if there was more than one. A failure that means the engine or the connection is gone
  still ends the listening, as before.
* **A message that arrives while no `serve`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-serve "Справочник команды: wa serve") runs is no longer lost.** WhatsApp keeps messages for a linked device
  while it is offline and hands each one over once, to the next connection. When that connection was a one-shot
  command (`messages send`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-messages-send "Справочник команды: wa messages send"), `doctor --online`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-doctor "Справочник команды: wa doctor"), an MCP session), `wa` received the messages and saved none of them. Now
  every connection saves what arrives, and the command waits for those saves before it exits (cli-core 0.343.0). A
  history push that arrives during such a command is saved too (above).
* **A file your phone uploaded again stays downloadable, once its new copy downloaded.** On the phones tried so far
  it does not (see the known limitation under `messages download`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-messages-download "Справочник команды: wa messages download")). `wa` keeps the new copy's address in the store,
  so a later `messages download`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-messages-download "Справочник команды: wa messages download") of it no longer asks the phone again, and `messages forward`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-messages-forward "Справочник команды: wa messages forward") sends a file that opens
  instead of the expired one. The same holds for `attachments extract --download`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-attachments-extract "Справочник команды: wa attachments extract"), `messages transcribe --local`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-messages-transcribe "Справочник команды: wa messages transcribe") and the
  picture index (`images embed`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-images-embed "Справочник команды: wa images embed")).
* **A history push after linking again keeps that address.** The phone pushes each file with the address it had
  before, and the store used to save it over the new one, so the next download asked the phone again. A message the
  store does not hold yet still takes the pushed address.
* **A download your phone could not give back says why, in its `reason`**, not only in its words. A file
  WhatsApp no longer keeps fails, per file in `batch.failures`, with `media.not-on-phone` (the phone has it no more),
  `media.phone-cannot-decrypt` (the phone could not read the request), `media.phone-failed` or
  `media.phone-answer-unreadable` (the phone answered an error), `media.phone-timeout` (no answer in 20 s),
  `media.retry-failed` (the new copy did not download) or `engine.stopped`; branch on those, never on the message.
  A download the phone's new upload served writes one line, `media.reuploaded`, to the engine's log when
  `WA_ENGINE_LOG` is set: the download's answer has no field for it.
* **A new copy that did not download says why.** The failure's message ends with the cause in fixed words: the HTTP
  status WhatsApp answered, a checksum or key that did not match, a file too short, a network error or the time
  running out, and whether the phone gave the expired path back. With `WA_ENGINE_LOG` set, a `media.refetch-failed`
  line adds the first download's cause and the phone's result. A phone that answered an error but still gave a path is tried as before; when that path
  does not download either, the reason is the phone's answer (`media.phone-failed`, `media.not-on-phone` or
  `media.phone-cannot-decrypt`), not `media.retry-failed`, which now means the phone said it uploaded the file.
* **A new copy that no longer matches the message's checksums is checked against the message's key before it is
  refused.** If the phone encrypted the old file again under the same key, `wa` accepts the copy when its MAC
  matches that key, which proves it was encrypted by someone holding the key, and stores the new checksums with the
  new address; a copy whose MAC does not match is still refused with `media.retry-failed` ("the file did not match
  its key"). On the phones tried so far, every new copy was encrypted under a different key and was refused this way
  (see the known limitation under `messages download`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-messages-download "Справочник команды: wa messages download")).
* **Node 22 no longer prints `ExperimentalWarning: SQLite is an experimental feature`** on every command that opens
  the store. Other warnings still print.
* **`wa mcp --help`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-mcp "Справочник команды: wa mcp") and the root help suggest `claude mcp add wa -- wa <profile> mcp`**, where they suggested a
  command without a profile that always failed.
* **The commands page labels `conversations embed`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-conversations-embed "Справочник команды: wa conversations embed"), `conversations build`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-conversations "Справочник команды: wa conversations"), `search conversations`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-search-conversations "Справочник команды: wa search conversations") and the model
  downloads as sending text to, or reading from, an outside service**, not as changes in WhatsApp.
* **A chat muted for good on the phone is stored as muted**, so `inbox`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-inbox "Справочник команды: wa inbox") leaves it out. The history the phone sends
  marks such a mute with an end no clock can read (WhatsApp writes -1 into an unsigned field), and `wa` took that for
  a mute that had already ended. Any end past the year 9999 now reads as muted with no end, as whatsmeow reads it in
  app state. How the phone writes it in history is not yet checked live.
* **A lock another process holds no longer stalls `serve`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-serve "Справочник команды: wa serve")** (cli-core 0.340.0): the send journal, the request pace
  and `recipients add`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-recipients-add "Справочник команды: wa recipients add") used to wait for it by blocking, so every relayed command and the connection's keep-alives
  stopped for up to 5 seconds. They now wait without blocking; the `timeout` (exit 9) is unchanged.
* **`setup`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-setup "Справочник команды: wa setup") without a terminal no longer waits 5 minutes on a dead connection after the history push** (cli-core
  0.340.0): the steps after it get the usual 30 seconds. At a terminal they stay unbounded.
* **The MCP `messages list`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-messages-list "Справочник команды: wa messages list") tool no longer offers `topic:`** (cli-core 0.340.0): WhatsApp has no forum topics, and a
  `topic:` term is refused as an unknown field, as on the command line.
* **`chats admins add`[↗](/llms.mdx/docs/ru/wa/commands-admin/content.md#wa-chats-admins-add "Справочник команды: wa chats admins add") has a summary that fits in 80 characters** (cli-core 0.340.0): "make a member an admin, with
  every right"; `--help` still names the seven rights.
* **A late answer from the phone no longer ends the next `messages sync`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-messages-sync "Справочник команды: wa messages sync") page early**: each request for older messages
  goes under its own id, and an answer that names an earlier request is saved like any history the phone sends instead
  of being taken for the current page. An empty late answer used to read as the chat's start. This holds if the phone
  names the request by that id, which is not yet checked live; otherwise answers are matched by their chat, as before.
* **A page the phone sends in pieces is filled**: when the phone sends fewer messages than asked, `wa` asks again from
  the oldest one it sent, one second apart, at most three asks and 25 seconds per page; what arrived before a
  timeout is kept.
* **A rate limit or a ban that ends `watch`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-watch "Справочник команды: wa watch") or `serve`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-serve "Справочник команды: wa serve")'s feed holds the next command's writes** as a one-shot
  command meeting it would.
* **`images embed`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-images-embed "Справочник команды: wa images embed") runs inside `serve`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-serve "Справочник команды: wa serve") when `serve`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-serve "Справочник команды: wa serve") holds the connection** (cli-core 0.337.0): it
  downloads pictures through WhatsApp, so it is a read from WhatsApp, and its MCP tool has no `offline` input.
* **Model downloads no longer go through a running `serve`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-serve "Справочник команды: wa serve")** (cli-core 0.336.0): `models text download`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-models "Справочник команды: wa models"), `models
  audio download`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-models "Справочник команды: wa models") and `images models download`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-images-models-download "Справочник команды: wa images models download") fetch from a model host, so they run in the calling process.
* **`wa chats list --json | head`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-chats-list "Справочник команды: wa chats list") ends quietly** (cli-core 0.328.0): through a running `serve`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-serve "Справочник команды: wa serve") the client kept
  writing into the closed pipe and printed a stack trace; it now exits 0.
* **The phone-number and agent prompts of `session start`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-session-start "Справочник команды: wa session start") and `setup`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-setup "Справочник команды: wa setup") go to the run's own stderr**, so a test or an
  embedding program that captures the run sees them.
* **`polls vote`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-polls-vote "Справочник команды: wa polls vote") and `polls voters`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-polls-voters "Справочник команды: wa polls voters") no longer mention anonymous polls** in their help and their agent tools
  (cli-core 0.328.0): WhatsApp has none.
* **`--json=item.<field>` keeps that field** (cli-base 0.44.0): `--json=item.profile` printed `item: {}`.
* **A query with a `/` that opens a regular expression and never closes it says to quote the value** (cli-base
  0.44.0): `text/plain` now hints `"text/plain"`. The error code and reason are unchanged.

### Added [#added-4]

* **`messages list <old id> --offline`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-messages-list "Справочник команды: wa messages list") finds the chat that id moved to**, and so does every other command that
  names a chat by the phone-number id it had before WhatsApp gave the person a LID. The store now keeps each chat's
  history: its id, title, membership, scope, search visibility and parent, one row per change. A read by an old id
  follows it within the account, also for a chat the account left when the command reads its kept history (cli-core
  0.368.0). Only a move the store
  recorded is followed: one `serve`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-serve "Справочник команды: wa serve") or `watch`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-watch "Справочник команды: wa watch") makes from now on, or one they repeat. The engine repeats the moves of
  the last 30 days at each start, so those are recorded at the first `serve`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-serve "Справочник команды: wa serve") or `watch`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-watch "Справочник команды: wa watch") start after the upgrade. An
  older move, and a number that was never a stored chat, still read as typed. The store moves to version 25 the
  first time this version opens it. That cannot be undone, so take a copy first (`wa <profile> store backup <file>`).
  `wa` 0.1.0 and older tg and max builds still open the upgraded store and write to it.
* **`wa <profile> store clear --left` lists the chats it would delete**, by id, title and message count, when it
  refuses without `--allow-dangerous`, and after deleting lists what it deleted; `--dry-run` lists them all and
  deletes nothing (cli-core 0.353.0).
* **`wa <profile> chats events <group>` lists who joined, left, was added, removed, promoted or demoted, and each new
  title**, from the local store, without connecting. `wa` keeps the group service messages the phone pushes with the
  history and, under `wa serve`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-serve "Справочник команды: wa serve") and `wa watch`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-watch "Справочник команды: wa watch"), each change as it happens; a change seen both ways is kept once.
  `wa watch --events`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-watch "Справочник команды: wa watch") prints them as `chat_event` lines, and `stats chats show`[↗](/llms.mdx/docs/ru/wa/commands-admin/content.md#wa-stats-chats-show "Справочник команды: wa stats chats show") counts the joins and leaves in
  `members`, where it used to leave them out. Changes from before the link that the phone did not push are not
  there. Engine protocol 33.
* **`wa <profile> messages send <chat> --sticker-file <file.webp>`** sends a `.webp` as a WhatsApp sticker, alone,
  with no text; agents send `sticker_file` through `wa_write` (`command: "messages send"`). It is a message like any
  other: the profile's permissions, the send journal and `--operation-id` apply, and so does the file guard
  (`--allow-any-file` for a file in `wa`'s own folders). A file that is not a WebP, or is larger than 500 KiB, is
  refused before connecting. A sticker to a channel is refused for now.
* **`wa <profile> chats update <group> --remove-photo`** takes a group's photo away; agents send `remove_photo`
  through `wa_write` (`command: "chats update"`). The members see it. It goes through the profile's permissions
  under `chats.update`, as `--photo` does, and is refused beside `--photo` before connecting. The photo goes first: if a
  title, description or setting given with it then fails, the error says the photo was removed.
* **`chats update --photo`[↗](/llms.mdx/docs/ru/wa/commands-admin/content.md#wa-chats-update "Справочник команды: wa chats update") and `account update --photo`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-account-update "Справочник команды: wa account update") say they take a `.jpg` or `.jpeg` file**, and refuse a file
  named otherwise, as they already refused one whose first bytes are not a JPEG's, before connecting. The engine still
  checks the photo is a square of 190 to 720 pixels a side.
* **`wa <profile> conversations rebuild`** builds, then embeds on this machine, the chats that changed and the group
  chats never built, or only `--chat`, bounded by `--max-chats` and `--max-chunks`. It sends nothing anywhere.
* **`setup`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-setup "Справочник команды: wa setup") and `session start`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-session-start "Справочник команды: wa session start") warn about bans before they show the QR code or the pairing code.** The warning
  says that `wa` is an unofficial client, that WhatsApp may ban an account for using one or for bulk or unsolicited
  messages, what `wa` does to keep the risk low, and what not to do. It goes to stderr once per link, in every
  output mode and with `--quiet` too, since it belongs to the code the person is about to scan; stdout and the JSON
  answer are unchanged. In machine mode, a link that fails after this point now has the warning on stderr before the
  error JSON, so read the error from the last line. A device that is linked already, and every later command, prints
  nothing new. The README, the installation and linking pages and the agent skill carry the same warning. The MCP
  page has its own: by default an agent may send up to 30 messages an hour without asking, and how to lower that.
* **`wa <profile> chats mute` and `chats unmute`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-chats-unmute "Справочник команды: wa chats unmute")**: stop a chat's notifications for good or `--until` a time (`2h`,
  `7d`, `2026-09-25T09:00`), and hear it again; agents run both through `wa_write`. It is the account's own
  setting, which WhatsApp syncs to the other devices; nobody in the chat is told (not yet checked live on the phone).
  It is a write and goes through the profile's permissions, under `chats.mute` and `chats.unmute`; a setting for
  `chats.mute` alone still covers both. A device linked minutes ago may not have WhatsApp's settings keys yet: the
  command then answers exit 12 with reason `settings.keys-missing` and says to keep `serve`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-serve "Справочник команды: wa serve") running a few minutes. A
  channel is muted on the phone.
* **`wa <profile> chats archive` and `unarchive`, `chats pin`[↗](/llms.mdx/docs/ru/wa/commands-admin/content.md#wa-chats-pin "Справочник команды: wa chats pin") and `unpin`, and `chats mark-unread`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-chats-mark-unread "Справочник команды: wa chats mark-unread")**: move a chat
  into WhatsApp's archive and back, keep it at the top of the chat list, or mark it unread, on the account's
  devices; nobody in the chat is told. Agents run them too, through `wa_write` (`command: "chats archive"` and the
  rest). `chats pin`[↗](/llms.mdx/docs/ru/wa/commands-admin/content.md#wa-chats-pin "Справочник команды: wa chats pin") pins the chat, not a message (`messages pin`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-messages-pin "Справочник команды: wa messages pin") does that). Archiving a chat also
  unpins it. Archive, unarchive and mark-unread name the chat's newest stored message, as `chats delete`[↗](/llms.mdx/docs/ru/wa/commands-admin/content.md#wa-chats-delete "Справочник команды: wa chats delete") does, and
  refuse a chat the store holds nothing of (exit 6); pin needs no message. WhatsApp's apps keep three pinned chats;
  `wa` does not count them. A mark-unread sends no receipt; `chats mark-read`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-chats-mark-read "Справочник команды: wa chats mark-read") takes the mark off (see Changed).
  Channels are refused. Each answers `settings.keys-missing` as `chats mute`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-chats-mute "Справочник команды: wa chats mute") does, and has its own
  permission key (`chats.archive`, `chats.unarchive`, `chats.pin`, `chats.unpin`, `chats.mark-unread`), allowed by
  default. Not yet checked live on the phone.
* **`wa <profile> chats delete` and `chats clear`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-chats-clear "Справочник команды: wa chats clear")**: delete a chat, or every message in it, from this account's
  devices; the others in it keep theirs. WhatsApp deletes up to a message it is told of, so `wa` names the chat's
  newest message in the local store, the owner's own or not, and refuses a chat the store holds nothing of (exit 6)
  rather than guess. A message that arrived after the store last heard should stay. `chats clear`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-chats-clear "Справочник команды: wa chats clear") deletes starred
  messages too; neither asks WhatsApp to delete the photos and files the phone saved from the chat. Both ask first
  at the default permission level (`chats.delete`, `chats.clear`; `--allow-dangerous` skips the question), are not
  offered over MCP, and answer `settings.keys-missing` as `chats mute`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-chats-mute "Справочник команды: wa chats mute") does. The local store keeps the chat's
  messages. Not yet checked live on the phone.
* **`wa <profile> messages star` and `messages unstar`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-messages-unstar "Справочник команды: wa messages unstar")**: star one message so it is easy to find again, or take the
  star off. It is the account's own mark, which WhatsApp syncs to the other devices; nobody in the chat is told. The
  message must be in the local store, since WhatsApp names it by its sender; one the store lacks is exit 6 and
  nothing is sent. A channel's post is starred on the phone. It goes through the profile's permissions
  (`messages.star`, `messages.unstar`), an agent can do it over MCP, and it answers `settings.keys-missing` as `chats
  mute`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-chats-mute "Справочник команды: wa chats mute") does. The local store keeps a star set with `wa`, so `messages list <chat> starred:true`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-messages-list "Справочник команды: wa messages list") and `search
  messages is:starred`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-search-messages "Справочник команды: wa search messages") find it. While `serve`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-serve "Справочник команды: wa serve") or `watch`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-watch "Справочник команды: wa watch") runs, a star set or taken off on the phone reaches the
  store too, and `watch --events --jsonl`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-watch "Справочник команды: wa watch") prints it as `{ "event": "star", "chatId", "chatTitle", "messageId",
  "starred" }`; the messages the phone pushes after linking keep their stars. The store moves to version 24
  for this the first time this version opens it; `wa` 0.1.0 still opens it. Not yet checked live on the phone.
* **`wa <profile> messages pin` and `messages unpin`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-messages-unpin "Справочник команды: wa messages unpin")**: a message in the local store is pinned for the whole chat; a
  message the store lacks is `not_found`. WhatsApp tells the chat's members about every pin, so each one notifies and
  counts toward the hourly limit; `messages pin`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-messages-pin "Справочник команды: wa messages pin") takes no `--notify`, and an agent's `wa_write` call no `notify`.
  `--expire-time 24h`, `7d` or `30d` (MCP `expire_time`) says how long it lasts; without it the pin lasts 7 days, as
  the help says; any other length is `validation_error`, over MCP before it connects.
* **`wa <profile> account privacy show` and `account privacy set`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-account-privacy-set "Справочник команды: wa account privacy set")**: who sees last seen (`--last-seen`), the
  profile photo (`--profile-photo`) and the about text (`--about-text`), whether online and last seen are hidden
  (`--hide-online`), whether read receipts go (`--read-receipts`; off also hides others' receipts from the owner, as
  on the phone), who may add the account to groups (`--chat-invites`) and whose calls ring (`--calls`). `show` asks
  WhatsApp each time, and reports a setting kept on the phone as "my contacts except…" as `contacts_except`, which
  `set` refuses; for groups that value is left out. `set` changes only the settings named and answers them all; it
  is a write under `permissions.account.privacy.set`. WhatsApp has no setting for who finds the account by its
  number or who sees the number, so `--find-by-phone` and `--phone-number` are not offered. Refused before anything
  is sent: `--chat-invites nobody` (WhatsApp is reported to refuse it), `--calls nobody`, and `--hide-online` with
  `--last-seen`, which both set last seen. `--calls contacts` sends the value meant as the phone's "silence unknown
  callers" (not yet checked on a real account). `--hide-online off` shows last seen to contacts. `set` sends one
  request per setting: if WhatsApp fails one, those sent before it stay changed, and the error says so; a change cut
  by a dropped connection answers `outcome_unknown` (exit 14), since it may have gone through.
* **`wa <profile> account update` sets the owner's WhatsApp name, about line and profile photo**: `--first-name` sets
  the name people see, with `--last-name` joined to it after a space (WhatsApp keeps one name, so a last name alone is
  refused), and `--description` the "about" line. The name is a setting WhatsApp syncs to the other devices; others
  probably see it only once the phone next comes online, since a device tells WhatsApp its name when it says it is
  online and `wa` never does (not checked live). `--photo` sets the profile photo (not checked live): `wa` takes
  a square JPEG of 190 to 720 pixels a side, as for a group's photo, checked before anything changes. The answer is
  the account with the new name. A device without WhatsApp's settings keys yet answers `settings.keys-missing`, as
  `chats mute`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-chats-mute "Справочник команды: wa chats mute") does; the name goes first, then the about, then the photo, and a step WhatsApp refuses after another
  changed says which did. The permission key is `account.update`.
* **`wa <profile> chats update <group> --photo <file>` sets the group's photo.** WhatsApp takes only a square JPEG
  of 190 to 720 pixels a side, and `wa` does not convert one: anything else is refused with `validation_error`
  before WhatsApp is asked, a PNG or WebP by its bytes whatever its name. The photo is set before the title,
  description or settings given with it, so a refused photo leaves the group unchanged, and a `--title` over 25
  characters is refused before the photo is set. If the rest of the change then fails, the error begins "the photo
  was set", keeping its code. It runs under the same permission and hourly limit as the rest of `chats update`[↗](/llms.mdx/docs/ru/wa/commands-admin/content.md#wa-chats-update "Справочник команды: wa chats update").
  `--remove-photo` takes it away (above).
* **A group says which WhatsApp community it is in.** A group linked to a community answers with `parent_chat_id`,
  the community's id; the community itself is a group with `provider_metadata.community: true`. They come with the
  group as WhatsApp gives it: the answers of `chats update`[↗](/llms.mdx/docs/ru/wa/commands-admin/content.md#wa-chats-update "Справочник команды: wa chats update"), `chats create`[↗](/llms.mdx/docs/ru/wa/commands-admin/content.md#wa-chats-create "Справочник команды: wa chats create") and `chats join`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-chats-join "Справочник команды: wa chats join"). `wa` also reads them
  from the history the phone pushes, so the local store keeps them and `chats list`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-chats-list "Справочник команды: wa chats list") and `chats show`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-chats-show "Справочник команды: wa chats show") show them, and
  follows WhatsApp's notices that a group joined or left a community (see Fixed). Listing a community's groups, and
  linking or unlinking one, are not built.
* **A photo and a video in one send go as an album** (`messages send --photo … --file clip.mp4`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-messages-send "Справочник команды: wa messages send")): one message that
  announces the album, then each file tied to it. The text is the photo's caption and the answer is the photo's
  message, under the send id. A repeat with the same `--operation-id` after an unknown outcome sends the same message
  ids, which WhatsApp takes as the same messages, as it does for a single send. A document beside a photo is still
  refused. Checked on a phone: it shows as one album.
* **A sent photo carries its preview**: the chat shows a small blurred picture before the download. Not yet for a
  video or a WEBP photo.
* **`wa <profile> metadata get` and `metadata refresh`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-metadata "Справочник команды: wa metadata")** read a group's title and description into the store for
  `tags auto`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-tags "Справочник команды: wa tags"); the group is not changed, and agents get both. A channel in the list answers with an error of its
  own.
* **`tasks agenda`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-tasks-agenda "Справочник команды: wa tasks agenda") lists what others owe you** (cli-core 0.328.0): `assigned` in JSON and an "assigned — others owe
  you" section hold the open tasks someone else does, oldest first, each with its `assignees`.
* **`wa commands --json`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-commands "Справочник команды: wa commands") has two new keys** (cli-base 0.44.0): `runnable: true` on a group that runs on its own, and
  `offline: false` on a command that cannot answer offline. A reader that rejects unknown keys must accept them.
* **`wa` follows and reads WhatsApp channels**, the one-way chats whose ids end in `@newsletter`: `chats join
  https://whatsapp.com/channel/<code>`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-chats-join "Справочник команды: wa chats join") follows one and `chats leave <channel>`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-chats-leave "Справочник команды: wa chats leave") unfollows it, both through the
  profile's permissions, and the channel's admins see that you followed. The channels you follow reach `chats list`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-chats-list "Справочник команды: wa chats list")
  as `kind: "channel"` when `serve`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-serve "Справочник команды: wa serve") or `watch`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-watch "Справочник команды: wa watch") connects. `messages sync <channel>`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-messages-sync "Справочник команды: wa messages sync") reads its posts into the local
  store from WhatsApp's servers, not from your phone: newest first, 50 at a time. Each post keeps its message id, and
  WhatsApp's number for it is in `provider_metadata.serverId`. Every post's sender is the channel, so a post you
  made shows `outgoing: false`. See [channels](/llms.mdx/docs/ru/wa/usage/content.md#channels).
* **`wa` posts to a WhatsApp channel you run**: `messages send <channel> <text>`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-messages-send "Справочник команды: wa messages send") asks WhatsApp for your role in the
  channel first and refuses anyone but its owner and admins with `permission_error` (exit 5) before anything is sent.
  The channel's followers see the post at once. Not a reply; a poll, a vote, a forward, an edit or a deletion in a
  channel is refused before anything is sent. A refused post still passes the profile's send permissions first, so
  under `ask` it asks before it is refused. Not yet checked live.
* **`wa` posts a photo, a video, a voice note or a file to a WhatsApp channel you run**: `messages send <channel> --photo/--file/--voice <path>`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-messages-send "Справочник команды: wa messages send"), the text as the caption. The role is asked first, as for a text post, so a channel
  you only follow is refused (exit 5) before anything is uploaded. A channel's files are not encrypted: `wa` uploads
  them as WhatsApp's apps do for channels, and the post carries no file key. One file per post; an album to a channel
  is refused (exit 2). A forward of a channel's file into a chat is refused too (exit 2,
  `media.channel-file-forward`), since it would arrive as a file that does not open. Not yet checked live: that needs
  a channel you own or administer.

## 0.1.0 — 17.10.2026 [#010--17102026]

### Changed — may break callers [#changed--may-break-callers-6]

* **The engine dying during a write answers `outcome_unknown`** (WC-LIFE-9): exit 14, `retry.safe: false`, the
  `operation_id` kept, reason `engine.stopped-mid-write`. It answered `provider_unavailable` (exit 12), which
  invited a retry and a double send. A read cut the same way still answers `provider_unavailable`.
* **Device and account states carry a `reason`** (WC-OUT-15), so an agent branches on it instead of the message:
  `device.in-use` (another `wa` process holds the login: stop it, or run the command through `serve`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-serve "Справочник команды: wa serve")),
  `engine.stopped`, `client.outdated` (update `wa`) and `device.replaced`, all `provider_unavailable`;
  `device.logged-out` (`authentication_error`); `account.banned` (`permission_error`); `account.rate-limited`
  (`rate_limited`). After WhatsApp ends the connection for one of these, later requests in the same process answer
  with it instead of connecting again. Engine protocol 10.
* **WhatsApp's rate limit and a ban hold the profile's sends** (WC-PERM-18). After WhatsApp asks the account to slow
  down, sends, edits and the other writes counted toward the send limit are refused for 15 minutes and reads go on;
  after a ban, until `wa <profile> doctor --online` connects again. Reactions and read receipts are not held.
  `doctor --online`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-doctor "Справочник команды: wa doctor") reports a ban as `standing.state: "frozen"` (it said `banned`, which held nothing).
  `wa <profile> flood clear` lifts either hold. Both lengths are a default the owner may change.
* **`commands --json`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-commands "Справочник команды: wa commands") marks more commands `mcp: false`** (cli-core 0.326.0, WC-MCP-2): `store`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-store "Справочник команды: wa store"), `server`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-server "Справочник команды: wa server"), `config`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-config "Справочник команды: wa config"),
  `mcp`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-mcp "Справочник команды: wa mcp"), `models`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-models "Справочник команды: wa models"), `images models`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-images-models "Справочник команды: wa images models"), `skill`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-skill "Справочник команды: wa skill"), `runs`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-runs "Справочник команды: wa runs"), `doctor report`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-doctor "Справочник команды: wa doctor"), `upgrade`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-upgrade "Справочник команды: wa upgrade"), `complete`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-complete "Справочник команды: wa complete"), `commands schema`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-commands "Справочник команды: wa commands"),
  `account sessions end`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-account-sessions "Справочник команды: wa account sessions"), and the commands that change a later run's authority (`recipients`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-recipients "Справочник команды: wa recipients"), `chats rules`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-chats-rules "Справочник команды: wa chats rules")). The
  MCP tool list `wa mcp`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-mcp "Справочник команды: wa mcp") serves is unchanged.
* **In a group tagged `watch-tasks`, any member's direct reply closes a question** (cli-core 0.325.0), with the
  resolution "answered in the group". Before, only your answer closed it; a later message that does not reply to the
  question still closes nothing.
* **A device linked before answers without counts** (WC-OUT-13). `session start --json`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-session-start "Справочник команды: wa session start") leaves out `received`, and
  `setup --json`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-setup "Справочник команды: wa setup") leaves out `history`, when the profile was already linked: nothing was pushed, so nothing was
  counted. They used to say 0, which read as "the phone pushed nothing".
* **Refusals that need a terminal say so in `reason`** (WC-OUT-15). `session start`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-session-start "Справочник команды: wa session start") and `setup`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-setup "Справочник команды: wa setup") without a terminal,
  and `session start phone`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-session-start "Справочник команды: wa session start") without one, answer `reason: "input.required"`; `--qr-file` with the phone method names
  `param: "--qr-file"`.
* **No automatic replies** (cli-core 0.324.0). `wa` no longer has `replies`, and `serve`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-serve "Справочник команды: wa serve") never answers by reply
  rules, even with `permissions.replies.send` at `allow`: WhatsApp bans accounts that answer like a bot, and `wa`
  sends nothing the owner did not ask for. A rules file left in the config folder is ignored.
* **Options WhatsApp has no counterpart for are no longer offered** (cli-core 0.324.0): `--silent` and `--send-as` on
  `messages send`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-messages-send "Справочник команды: wa messages send"), `messages forward`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-messages-forward "Справочник команды: wa messages forward") and `polls create`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-polls-create "Справочник команды: wa polls create"), `--at-time` on `messages send`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-messages-send "Справочник команды: wa messages send"), `--anonymous` on
  `polls create`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-polls-create "Справочник команды: wa polls create"), and the commands `chats send-as`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-chats "Справочник команды: wa chats") and `messages scheduled`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-messages "Справочник команды: wa messages"). They were refused before; now they are
  unknown, still with exit 2, and the MCP tools no longer take `silent`, `send_as`, `at_time` or `anonymous`.
* **Commands WhatsApp lacks refuse before connecting** (cli-core 0.324.0): `account update`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-account-update "Справочник команды: wa account update"), `account sessions list`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-account-sessions-list "Справочник команды: wa account sessions list")
  and `end`, `chats events`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-chats-events "Справочник команды: wa chats events"), `chats inspect`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-chats-inspect "Справочник команды: wa chats inspect"), `chats folders *`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-chats-folders "Справочник команды: wa chats folders"), `contacts add`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-contacts-add "Справочник команды: wa contacts add"), `remove`, `rename` and `import`,
  `messages pin`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-messages-pin "Справочник команды: wa messages pin") and `unpin` refuse with exit 2 before connecting to WhatsApp.
* **`watch --events`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-watch "Справочник команды: wa watch") no longer prints the votes of the phone's history push** (cli-core 0.322.0). They were
  printed as new votes; they are old ones, and the store now saves them with the push, together with their poll and
  dated when each person voted, so an older one never replaces a newer live vote. A script that read history votes
  from `watch`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-watch "Справочник команды: wa watch") reads `polls voters`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-polls-voters "Справочник команды: wa polls voters") instead. Engine protocol 9.
* **An agent never deletes for everyone** (cli-core 0.321.0). Every WhatsApp delete `wa` makes is for everyone, so
  `messages delete`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-messages-delete "Справочник команды: wa messages delete") through MCP is refused with `permission_error`, before `wa` connects, whatever the profile's
  level; the owner still has `wa <profile> messages delete --for-everyone`.
* **`mcp --permission <key=level>`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-mcp "Справочник команды: wa mcp") only narrows** (cli-core 0.321.0). An override that would give the server more
  than the profile — `readonly` to `allow`, a `deny` to anything — stops it at startup with `validation_error` naming
  the key. To let an agent do more, set the level in the profile. The browser setup no longer starts the server with
  `--permission messages.send=allow`.
* **Tasks open only where something is asked of you** (cli-core 0.318.0). In a one-to-one chat every question you did
  not answer opens one, as before; in a group only a question in reply to your message and a mention of you; in a
  channel or the chat with yourself nothing.
* **`tasks apply`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-tasks "Справочник команды: wa tasks") is now `tasks scan`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-tasks-scan "Справочник команды: wa tasks scan")** (cli-core 0.320.0); MCP `tasks_scan`, permission key `tasks.scan`.
* **No setting picks a profile any more** (cli-core 0.319.0). A command names its profile with the first word or
  `WA_PROFILE`. A config file that still has `default_profile` stops a command that names no profile, with the profile
  to type and `wa config unset default_profile`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-config-unset "Справочник команды: wa config unset"); `wa config set default_profile`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-config-set "Справочник команды: wa config set") is refused. A profile called `default`
  is an ordinary name: `wa default mcp config` names its server `wa-default`, not `wa`.
* **`polls close`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-polls "Справочник команды: wa polls") and `polls create --revote`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-polls-create "Справочник команды: wa polls create") are gone** (cli-core 0.317.0): a WhatsApp poll never closes and every
  vote can change. A script that closed a poll or asked for revoting drops that call.
* **`chats admins add`[↗](/llms.mdx/docs/ru/wa/commands-admin/content.md#wa-chats-admins-add "Справочник команды: wa chats admins add") takes no `--can`**: a WhatsApp admin has every right, so it gives them all. A script that
  passed `--can` drops it.

### Security [#security-2]

* **`WA_ENGINE_LOG` no longer writes phone numbers** (WC-SECR-1): every user id (phone, device and hidden-id forms)
  and any other long run of digits is masked before a line reaches the file.
* **A release from GitHub Actions publishes the engine packages validation built and tested** (WC-REL-12): it checks
  each against the SHA-256 that validation recorded, and builds nothing again. This first release was published from
  the maintainer's machine, which builds them itself.
* **`WA_READ_ONLY` also stops linking and unlinking the device**: `session start`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-session-start "Справочник команды: wa session start") and `setup`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-setup "Справочник команды: wa setup") refuse to link a new
  device, and `session end`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-session-end "Справочник команды: wa session end") refuses to log out, with `permission_error`.
* **An interrupted or timed-out login closes the engine and removes its QR image**, instead of leaving both behind.
* **The account name shown after linking is printed as plain text**, never as terminal control codes.
* **Media keys stay inside the client**: internal attachment references stay out of live-event, JSON and MCP output
  (cli-core 0.315.0).
* **Invite links must name WhatsApp's exact invite host**; unrelated URL prefixes are refused before connecting.
* **WhatsApp state is safe from the other messengers' uploads** (cli-core 0.314.0), and a running server's read-only
  lock holds when a command is relayed to it.
* **The Go engine builds with Go 1.26.9 and `golang.org/x/net` 0.60.0**, clearing the affected runtime and
  networking advisory paths while retaining the current Go release branch.

### Fixed [#fixed-6]

* **`session end`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-session-end "Справочник команды: wa session end") no longer runs through a running `serve`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-serve "Справочник команды: wa serve")**: it logged out `serve`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-serve "Справочник команды: wa serve")'s own connection and then
  deleted the device keys under it. It now refuses with `provider_unavailable`, reason `device.in-use` (exit 12),
  and says to stop `serve`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-serve "Справочник команды: wa serve") first (`wa <profile> server stop`, or Ctrl+C).
* **The command reference no longer says `defaultProfile` in the config file picks a profile** (WC-ACCT-1): no
  setting does; the first word or `WA_PROFILE` names it.
* **Refusals name the whole command to run next**: `wa <profile> chats list`, `wa <profile> serve` and
  `wa <profile> session start`, where they said only `chats list`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-chats-list "Справочник команды: wa chats list"), `serve`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-serve "Справочник команды: wa serve") or `session start`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-session-start "Справочник команды: wa session start").
* **No `messages sync`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-messages-sync "Справочник команды: wa messages sync") advice `wa` cannot follow** (cli-core 0.322.0): where a command points at the store's gaps it
  names `messages sync <chat>`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-messages-sync "Справочник команды: wa messages sync") for one chat, never `--all`.
* **`wa upgrade`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-upgrade "Справочник команды: wa upgrade")'s "held back" hint names the package and keeps pnpm's release-age exemption** (cli-core 0.320.0).
* **An agent's `chats members list`[↗](/llms.mdx/docs/ru/wa/commands-admin/content.md#wa-chats-members-list "Справочник команды: wa chats members list") and `chats send-as`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-chats "Справочник команды: wa chats") follow their own permission keys**, `chats.members.list` and
  `chats.send-as`, so a deny on those keys reaches the MCP agent too (cli-core 0.321.0).
* **A reply names the quoted message's sender and carries its text** when the local store holds that message, so
  phones show the quote instead of "unavailable"; a reply to one the store lacks still goes, with the message's id
  alone.
* **An edit keeps the message's own time**: one that `serve`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-serve "Справочник команды: wa serve") or `watch`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-watch "Справочник команды: wa watch") hears keeps the message's time, reply and
  reactions in the local store; before, it took the edit's time as the message's.
* **Tests on Windows check file access rules** instead of Unix mode bits. Group administration tests verify
  stranger refusals and unsupported changes before writes.
* **The search and query language pages said the file fields find nothing**; `has:file`, `filename:`, `mime:` and
  `content:` work on every message stored since `wa` handled files. The README and the docs start page no longer list
  files and group administration as coming next.
* **Release and monthly source checks include the Go engine**, using its module toolchain. Local tests resolve the
  shared TypeScript config directly so they run in isolated worktrees.

### Added [#added-5]

* **`wa <profile> flood clear`** (cli-core's, as in tg and max): forgets the waits WhatsApp asked for and lifts the
  hold on writes. The refusal during a hold already named it; `wa` did not have it.
* **`session`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-session "Справочник команды: wa session"), `session start`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-session-start "Справочник команды: wa session start"), `session end`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-session-end "Справочник команды: wa session end") and `setup`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-setup "Справочник команды: wa setup") carry `mcp: false`** in `commands --json`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-commands "Справочник команды: wa commands") (WC-CMD-21):
  linking waits for a person and unlinking removes the owner's device, so neither will be offered to an agent once
  MCP tools are built from commands. `setup`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-setup "Справочник команды: wa setup") and `upgrade`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-upgrade "Справочник команды: wa upgrade") list examples there too (WC-CMD-24).
* **The engine packages are GPL-3.0-only**: `@wirecat/whatsapp-engine-*` and the `engine/` folder they are built
  from, because the engine links `go.mau.fi/libsignal` (GNU General Public License 3.0). Each package carries the
  GPL text as `LICENSE` and a README that points at the commit it was built from. `@wirecat/whatsapp-cli`
  stays Apache-2.0: it runs the engine as a separate program over stdin and stdout, and its package never carries
  the engine.
* **Each engine package carries `THIRD_PARTY_NOTICES`**: the licence of every Go module the engine links and of Go
  itself, with where each module's source is. whatsmeow and `go.mau.fi/util` are under the Mozilla Public License
  2.0 and `go.mau.fi/libsignal` under the GNU General Public License 3.0, all unmodified.
* **Tasks have assignees** (cli-core 0.320.0): `tasks add`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-tasks-add "Справочник команды: wa tasks add") and `tasks plan`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-tasks "Справочник команды: wa tasks") take `--assignee sender` (whoever sent
  the message) or `--assignee person:<id>`; `none` clears it. `tasks list "assignee:any state:open"`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-tasks-list "Справочник команды: wa tasks list") is what others
  owe you.
* **`wa <profile> tags add --chat <group> watch-tasks`** records every question in that group as a task, whoever it
  is for.
* **Poll votes are counted**: `serve`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-serve "Справочник команды: wa serve") and `watch`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-watch "Справочник команды: wa watch") keep each person's newest vote, from the phone's history push and
  as votes arrive (`watch --events`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-watch "Справочник команды: wa watch") prints them), so `polls show`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-polls-show "Справочник команды: wa polls show") counts the answers and says which you chose, and
  the new `polls voters`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-polls-voters "Справочник команды: wa polls voters") lists who voted for what. A poll made with `polls create`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-polls-create "Справочник команды: wa polls create") is kept in the local store, so it
  can be shown and voted on. Engine protocol 8; cli-core 0.317.0.
* **Commands while `serve`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-serve "Справочник команды: wa serve") runs**: a send, an edit, a reaction, `watch`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-watch "Справочник команды: wa watch"), `wa <profile> mcp` and every other command
  that connects run inside a running `serve`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-serve "Справочник команды: wa serve"), on its one connection, instead of being refused. Permissions and the
  send guard still apply; a write at `ask` needs `--yes`. On Windows they do not go through `serve`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-serve "Справочник команды: wa serve").
* **The foundation**: the shared cli-core commands over a WhatsApp adapter that reads from the local store, an
  engine contract, and the same linters, checks and CI as tg-cli and max-cli.
* **Older history from the phone**: `wa <profile> messages sync <chat>` asks the phone for the 50 messages of a chat
  before the oldest one the local store holds, page after page, and waits up to 30 seconds for each answer (engine
  protocol 5; cli-core 0.316.0). `--all` is refused: WhatsApp has no chat list to walk.
* **More group settings**: `chats update --only-admins-send`[↗](/llms.mdx/docs/ru/wa/commands-admin/content.md#wa-chats-update "Справочник команды: wa chats update"), `--only-admins-edit-info` and `--disappear-time`
  (24h, 7d or 90d, the times WhatsApp offers; `off` keeps messages). A group's answer shows them in `settings`
  instead of `provider_metadata`. Engine protocol 7.
* **The WhatsApp engine**: `wa` connects through a Go program built on whatsmeow, started for each command that
  connects and stopped when it ends. One command at a time may connect a profile; a second is told which one holds it.
* **Installs with its engine**: `npm install --global @wirecat/whatsapp-cli` also installs the engine for your system,
  a small package of its own, for Linux, macOS and Windows on x64 and arm64. `WA_ENGINE` still runs another one. A
  global install also installs the agent skill and, on Windows, puts `wa` on the user's PATH, as tg does.
* **`wa <profile> session start [qr|phone]`** links the profile by QR code or pairing code and keeps the history the
  phone sends right after linking. **`session end`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-session-end "Справочник команды: wa session end")** unlinks the device and deletes its keys.
* **Changing messages**: `messages edit`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-messages-edit "Справочник команды: wa messages edit") (your own, within WhatsApp's 20 minutes), `messages delete --for-everyone`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-messages-delete "Справочник команды: wa messages delete")
  (your own, or another's in a group you administer), `reactions add`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-reactions-add "Справочник команды: wa reactions add") and `reactions remove`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-reactions-remove "Справочник команды: wa reactions remove"), and `chats mark-read`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-chats-mark-read "Справочник команды: wa chats mark-read")
  and `--mark-read`, which send a read receipt only when asked. Each needs the message in the local store, which
  `serve`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-serve "Справочник команды: wa serve") keeps filled; WhatsApp addresses a message by its sender. Deleting for you alone is not built yet.
* **Files**: photos, videos, voice notes, audio, documents and stickers arrive as attachments, with places and contact
  cards named; `messages send --file`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-messages-send "Справочник команды: wa messages send"), `--photo` and `--voice` send one file with its caption; `messages download`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-messages-download "Справочник команды: wa messages download")
  saves a stored message's file; `messages transcribe --local`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-messages-transcribe "Справочник команды: wa messages transcribe") reads a voice note with a model on this machine
  (`wa models`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-models "Справочник команды: wa models")); `messages forward`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-messages-forward "Справочник команды: wa messages forward") sends a stored message again, marked forwarded, file included; `wa images`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-images "Справочник команды: wa images") searches
  pictures by what they show. The engine protocol is now 3.
* **Groups and people**: `chats create`[↗](/llms.mdx/docs/ru/wa/commands-admin/content.md#wa-chats-create "Справочник команды: wa chats create"), `join`, `leave`, `update` (name, description, admin-only adds, join
  approval), `chats link show|reset`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-chats "Справочник команды: wa chats"), `chats members add|remove`[↗](/llms.mdx/docs/ru/wa/commands-admin/content.md#wa-chats-members "Справочник команды: wa chats members"), `chats admins add|remove`[↗](/llms.mdx/docs/ru/wa/commands-admin/content.md#wa-chats-admins "Справочник команды: wa chats admins"), `chats requests
  list|accept|decline`[↗](/llms.mdx/docs/ru/wa/commands-admin/content.md#wa-chats-requests "Справочник команды: wa chats requests"), `contacts profile`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-contacts "Справочник команды: wa contacts"), `contacts block|unblock`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-contacts "Справочник команды: wa contacts"), `contacts lookup`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-contacts-lookup "Справочник команды: wa contacts lookup") and `contacts sync`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-contacts-sync "Справочник команды: wa contacts sync") (the
  phone's address book), and `doctor --online`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-doctor "Справочник команды: wa doctor") now connects to check the account. Group changes go through the send
  guard like a send; adding people is refused for anyone not in the address book or written to before, since
  WhatsApp bans accounts that add strangers. A number lookup is one per call, one every 10 seconds per profile.
  Engine protocol 4.
* **Formatting and polls**: `messages send --md`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-messages-send "Справочник команды: wa messages send") and `messages edit --md`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-messages-edit "Справочник команды: wa messages edit") write Markdown as WhatsApp's own marks
  (bold, italic, strike, code, quotes; a link becomes its label and address; underline and spoilers become plain
  text). `polls create`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-polls-create "Справочник команды: wa polls create") (one answer or `--multiple`), `polls show`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-polls-show "Справочник команды: wa polls show") and `polls vote`[↗](/llms.mdx/docs/ru/wa/commands-personal/content.md#wa-polls-vote "Справочник команды: wa polls vote") (`--retract` too) work on polls
  in the local store. Engine protocol 6.
* **`wa <profile> setup`** is the guided first run, as in tg: it checks this computer, links the device or reuses it,
  reads the account and five chats from the local store, and installs the agent skill (`--agent`). Agents use
  `--qr-file`.
* **`wa upgrade`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-upgrade "Справочник команды: wa upgrade")** installs the newest version with the package manager that installed `wa` and restarts running
  servers; a daily line on stderr says when a newer version exists.
* **`wa doctor`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-doctor "Справочник команды: wa doctor")** reports whether the engine program is found, whether the device keys exist with private file
  modes, and who last held the device's lock and whether that process still runs.
* **Documentation like tg's**: pages on linking and profiles, the local store, search and its query language,
  groups, people, MCP and the browser, permissions, limits, the CLI contract, diagnostics and recipes, each limited
  to what WhatsApp can do today. The agent skill (`wa skill show`[↗](/llms.mdx/docs/ru/wa/commands-setup/content.md#wa-skill-show "Справочник команды: wa skill show")) is rebuilt on tg's: setup without a terminal,
  the traps, the exit codes, and what one connection per device means for an agent.
* **A page on file attachments** ([docs/attachments.md](/llms.mdx/docs/ru/wa/attachments/content.md)): sending one file per message, what the
  local store keeps, downloading, forwarding, voice notes as text with a model on this machine, and reading the text
  of files for `content:` search. The README gains tg's sections on linking and profiles, groups you run, limits
  and the list of pages.
