# Custom emoji

`slackcli emoji` reads and manages a workspace's **custom emoji** — the ones an admin or
member uploaded, not the built-in Unicode set.

```bash
slackcli emoji list
slackcli emoji list --filter kiro
slackcli emoji list --limit=50
slackcli emoji list --no-aliases
slackcli emoji list --json
slackcli emoji get party-parrot
slackcli emoji get :party-parrot: --json
```

## `emoji list`

Lists every custom emoji in the workspace, sorted by name. `--no-aliases`,
`--filter` and `--limit` are applied locally to the full list, in that order.
A workspace with no custom emoji prints nothing on stdout, even with `--json`.

`--filter <substring>` keeps emoji whose **name** contains the substring,
matched case-insensitively. It is a local match over the full in-memory list,
not a Slack search (Slack's API has no emoji search), so it does the same thing
the composer's `:name…` autocomplete does. Surrounding
colons are stripped as in `emoji get`, so `--filter :kiro:` and `--filter kiro`
behave the same; an empty value (or one that is only colons/whitespace) is
rejected rather than matching everything.

| Option | Purpose |
|---|---|
| `--limit <number>` | Maximum number of emoji to return |
| `--filter <substring>` | Only emoji whose name contains this substring (case-insensitive) |
| `--no-aliases` | Exclude alias emoji, showing only originals |
| `--workspace <id\|name>` | Workspace to use |
| `--json` | JSON output |
| `--fields <list>` | With `--json`, only these comma-separated fields (dot paths allowed) |

## `emoji get <name>`

Shows one emoji's details — whether it is an original (with its image URL) or an
alias (with the emoji it points at). The name matches with or without the
surrounding colons, so both `party-parrot` and `:party-parrot:` work.

| Option | Purpose |
|---|---|
| `--workspace <id\|name>` | Workspace to use |
| `--json` | JSON output |
| `--fields <list>` | With `--json`, only these comma-separated fields (dot paths allowed) |

## Aliases

Slack's `emoji.list` returns two kinds of value per name: an image URL for an
original custom emoji, or the string `alias:<target>` for an alias that reuses
another emoji's image. SlackCLI normalises both into a typed entry — `is_alias`
distinguishes them, and `alias_for` names the target — so the terminal output
and the `--json` schema stay the same regardless of which kind it is.

Both auth types work: `emoji.list` is available to standard (`xoxb`/`xoxp`) and
browser (`xoxd`/`xoxc`) tokens alike.

## `emoji add <name>`

Adds a custom emoji — either a new image or an alias of an existing emoji.
**Browser authentication only**: Slack's custom-emoji write endpoint
authenticates with a browser session, so a standard app token is refused with
a clear message. This is a regular workspace-member action on most workspaces,
not an Enterprise-Grid admin action.

```bash
slackcli emoji add party-kiro --file ./party-kiro.png
slackcli emoji add r7 --alias-for rapid7
slackcli emoji add party-kiro --file ./party-kiro.png --json
slackcli emoji add party-kiro --file ./party-kiro.png --dry-run
```

`--file` and `--alias-for` are mutually exclusive; exactly one is required.
The name may use only lower-case letters, digits, dashes and underscores. A
`--file` image larger than Slack's 128×128 / 64 KB guidance is warned about,
not blocked — Slack downscales it.

| Option | Purpose |
|---|---|
| `--file <path>` | Local image to upload as a new emoji |
| `--alias-for <existing>` | Create an alias of this existing emoji |
| `--workspace <id\|name>` | Workspace to use |
| `--json` | JSON output: `{ name, is_alias, alias_for? }` |
| `--dry-run` | Show what would be done without doing it |

## `emoji remove <name>`

Removes a custom emoji. **Browser authentication only.** Idempotent: removing
one that does not exist succeeds as a no-op (exit 0), the same contract as
`messages unreact` and `messages delete`. A policy refusal such as
`enterprise_is_restricted` is a real `permission_denied` failure (exit 1).

Removal affects the whole workspace, so it asks for confirmation; pass `--yes`
to skip the prompt (required when stdin is not a terminal).

```bash
slackcli emoji remove party-kiro
slackcli emoji remove :party-kiro: --yes --json
slackcli emoji remove party-kiro --dry-run
```

| Option | Purpose |
|---|---|
| `--yes` | Remove without the confirmation prompt |
| `--workspace <id\|name>` | Workspace to use |
| `--json` | JSON output: `{ name, removed, already_removed }` |
| `--dry-run` | Show what would be done without doing it |