Skip to main content

cli-recipes

This skill should be used when the user asks about the "Chatwoot CLI", "chatwoot command line", "chatwoot convs/conv/contact commands", "triage Chatwoot from the terminal", "run Chatwoot in CI", or needs ready-to-use `chatwoot` CLI commands, the noun/verb grammar, output-format rules, or safety guidance for customer-visible writes.

Source facts

Repository
Agents-Store/codex-plugins
Last source activity
November 1, 2026 at 02:46
Detected SKILL.md language
English
Stars
0
Forks
0

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

File Explorer
2 files

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
cli-recipes
description
This skill should be used when the user asks about the "Chatwoot CLI", "chatwoot command line", "chatwoot convs/conv/contact commands", "triage Chatwoot from the terminal", "run Chatwoot in CI", or needs ready-to-use `chatwoot` CLI commands, the noun/verb grammar, output-format rules, or safety guidance for customer-visible writes.
# Chatwoot CLI Recipes Operate Chatwoot helpdesks from the terminal with the official `chatwoot` CLI — list and triage conversations, send replies and notes, assign, change status, set labels/priority, search contacts, inspect inboxes, and search help-center articles. > Adapted from the official Chatwoot `chatwoot-cli` agent skill (MIT, https://github.com/chatwoot/cli). > The CLI is in active development — run `chatwoot --help` to confirm flags for your version. > > Use **CLI v0.7.0 or newer** (released 2026-09-25): it adds the per-conversation write lock > described below and sends the auth header as `api-access-token` (hyphens), so it works behind > proxies that drop underscore headers (nginx default, Caddy 2.6.4+). Older versions get `401` > there. ## Install & authenticate ```bash # macOS / Linux — detects OS/arch, verifies SHA256 curl -fsSL https://chwt.app/install-cli | sh # Interactive setup (prompts for Base URL, API Key, Account ID). # Non-secret config -> ~/.chatwoot/config.yaml; API key -> OS keyring. chatwoot auth login # CI / headless / agent contexts — bypass the keyring with the env var. # auth login is interactive and FAILS in non-TTY; never script it. export CHATWOOT_API_KEY="your_access_token" ``` ## Agent output contract The CLI defaults to **human-readable text**. It does NOT auto-switch to JSON in non-TTY environments. When a script or agent will consume the output, opt in explicitly: - `-o json` — parse with `jq`. Never grep the text format (it is for humans and can change). - `-q` — IDs only, one per line, for piping to `xargs` or chaining `chatwoot` calls. - `-o csv` — spreadsheet-friendly. - Exit `0` = success; non-zero = error (errors go to stderr). - `-v` (verbose) shows the underlying HTTP request/response when debugging. ### Per-conversation locks (v0.7.0) Every mutating `conv` verb (`reply`, `resolve`, `open`, `pending`, `snooze`, `assign`, `unassign`, `label`, `priority`) takes a lock on that conversation first (files under `~/.chatwoot/locks/`, released by the OS if the process dies). A second mutation of the **same** conversation from another terminal or agent fails immediately instead of running in parallel, so: - Treat that failure as "someone else is writing", not as an error to retry in a tight loop; re-read the conversation, then decide. - Different conversations are not blocked by each other, so bulk work across many conversations still runs in parallel. - Locks are local to one machine's `~/.chatwoot/`; they do not coordinate two machines. ## Grammar Every command is one of three shapes: | Shape | Meaning | Example | |-------|---------|---------| | `<plural-noun>` | list | `chatwoot convs`, `chatwoot contacts` | | `<singular-noun> <id>` | view | `chatwoot conv 123` | | `<singular-noun> <id> <verb> [..]` | act | `chatwoot conv 123 reply "hi"` | The id always comes **before** the verb. Nouns: `conv`/`convs`, `contact`/`contacts`, `inbox`/`inboxes`, `agents`, `labels`, `teams`, `hc`/`hcs`. ## Global flags | Flag | Description | |------|-------------| | `-o, --output` | `text` (default), `json`, `csv` | | `-a, --account` | Override account ID for this invocation | | `-q, --quiet` | IDs only, one per line | | `-v, --verbose` | Show request/response (debugging) | | `--no-color` | Disable colored output | ## Command reference | Command | What it does | |---------|--------------| | `convs` | List conversations (filters: `-s` status, `--inbox`, `--assignee`, `--team`, `-l` label, `--query`, `-p` page) | | `conv <id>` | View one conversation | | `conv <id> messages` | List messages in a conversation | | `conv <id> reply <text>` | Send a public reply (`--private` for an internal note) | | `conv <id> resolve` \| `open` \| `pending` | Change status | | `conv <id> snooze [--until X]` | Snooze (default: until next reply; pass `--until 7d` for a fixed window) | | `conv <id> assign` | Assign `--agent me\|alice\|42` and/or `--team 7` | | `conv <id> unassign` | Remove the assignee | | `conv <id> label <a,b,c>` | **Replace** labels with this set (comma-separated, single flag) | | `conv <id> priority <level>` | `urgent` \| `high` \| `medium` \| `low` \| `none` | | `conv <id> contact` | View the sender contact | | `contacts` | List/search contacts (`--search "name\|email\|phone"`) | | `contact <id> [conversations]` | View a contact / list their conversations | | `inboxes` \| `inbox <id>` | List inboxes / view one | | `agents` \| `labels` \| `teams` | List account-level resources | | `hcs` \| `hc default [slug]` \| `hc articles [--query]` \| `hc article <slug>` | Help-center listing & search | | `me` \| `whoami` \| `auth status` | Current identity / session | | `api <path>` | Call any Chatwoot endpoint with saved auth (account-relative path) | | `auth login` \| `logout` | Interactive login / remove credentials | | `config path` \| `config view` | Inspect config file | ## Common patterns List responses are wrapped in `.data.payload[]`: ```bash chatwoot convs --assignee me -s open -o json \ | jq '.data.payload[] | {id, contact: .meta.sender.name, last: .messages[-1].content}' chatwoot convs --query "refund" --assignee all -s open -q # IDs only ``` Read recent messages (`message_type`: `0` customer, `1` agent, `2` activity, `3` template): ```bash chatwoot conv 123 messages -o json \ | jq '.payload[-5:][] | {dir: (if .message_type==0 then "in" else "out" end), private, content}' ``` Append a label (the `label` verb **replaces** — fetch first, then merge). `set -o pipefail` is required so a failed fetch surfaces instead of silently clearing every label: ```bash set -o pipefail existing=$(chatwoot conv 123 -o json | jq -r '.labels // [] | join(",")') chatwoot conv 123 label "${existing:+$existing,}billing" ``` Bulk resolve via `-q | xargs` (list what would be affected first, then confirm): ```bash chatwoot convs -l spam -q | xargs -I{} chatwoot conv {} resolve ``` Chain contact → conversations: ```bash id=$(chatwoot contacts --search "jane@example.com" -o json | jq '.payload[0].id') chatwoot contact "$id" conversations -o json ``` Raw API call — account-relative paths expand under `/api/v1/accounts/<account_id>`, so do not include that prefix. Prefer first-class commands; use `api` only when no command exists: ```bash chatwoot api /conversations/123 -o json chatwoot api -X PATCH /conversations/123 --data '{"status":"open"}' ``` ## Common mistakes 1. **Parsing text output** — always `-o json` (or `-q`) when an agent consumes output. 2. **`convs` defaults to your open queue** — it is implicitly `--assignee me -s open`. Pass `--assignee all` + the right `-s` for "everything". 3. **`label` replaces, not appends** — fetch-then-merge (see above). 4. **`--query` ≠ contact search** — `convs --query` searches message content; use `contacts --search` for a person. 5. **Ambiguous `--agent <name>`** — matches a case-insensitive substring; prefer agent IDs in scripts (`chatwoot agents -o json` to resolve). 6. **Labels are comma-separated on one flag** — `-l a,b`, not `-l a -l b`. 7. **A list is one page** — inspect `meta` and advance with `-p N`. 8. **Bare `snooze` is not forever** — it snoozes until the next reply; pass `--until`. 9. **Never run `auth login` in a script** — use `CHATWOOT_API_KEY` + saved config (or `-a`). 10. **A second write to the same conversation fails fast** — v0.7.0 locks per conversation; don't launch two mutating commands on one conversation in parallel (see "Per-conversation locks"). ## Safety — customer-visible writes Treat all writes as privileged. Before running any of these in an agent context, **show the exact command and get explicit approval**. Approval on one conversation does not extend to another. Irreversible / customer- or team-visible: `reply` (sent, cannot be unsent — confirm tone), `assign`/`unassign` (queues, notifications), `resolve`/`open`/`pending`/`snooze` (status, SLA), `label` (overwrites the set), `priority` (dashboards, SLA routing), `api -X <method>` or `api --data` (treat non-GET as a write), and any `-q | xargs` bulk operation. Read-only and safe to run freely: `convs`, `conv <id>` view, `conv <id> messages`, `conv <id> contact`, `contacts`, `contact <id>`, `inboxes`, `inbox <id>`, `agents`, `labels`, `teams`, `me`, `whoami`, `auth status`, `config path/view`, and `api <path>` GETs.
View on GitHub