# dsc tag

Manage the tag taxonomy (tags and tag groups) as a version-controlled file. For applying/removing a tag on a specific topic, see [`dsc topic tag/untag`](topic.md#dsc-topic-tag).

## dsc tag list

```text
dsc tag list <discourse> [--format text|json|yaml]
```

Lists all tags visible to the authenticated user, with the topic count beside each. Default text output is two columns (tag name, count) and is sortable/cuttable.

## dsc tag pull

```text
dsc tag pull <discourse> [path]
```

Serialises the full tag taxonomy (tags and tag groups) to a single file. Default path: `tags.yaml`. Format is inferred from the file extension (`.yaml`/`.yml` or `.json`).

Only definitions are emitted — usage counts and read-only fields are excluded so repeated pulls stay diff-clean.

Tag groups require an admin API key. If the key lacks admin scope, groups are omitted with a warning.

```bash
dsc tag pull myforum
dsc tag pull myforum tags.json
```

### File schema (version 1)

```yaml
version: 1

tags:
  - name: covers
    description: Topics with cover images

tag_groups:
  - name: Role
    one_per_topic: false
    parent_tag: null
    permissions:
      everyone: full
    tags:
      - guitarist
      - bassist
```

## dsc tag push

```text
dsc tag push <discourse> <path> [--prune]
```

Reads a taxonomy file and reconciles server state toward it.

- **Default (upsert)**: creates missing tags/groups, updates changed ones, never deletes.
- **`--prune`**: additionally deletes tags and tag groups present on the server but absent from the file.
- Idempotent: a push with no file change is a no-op.
- Supports `--dry-run` (`-n`) to preview the plan without sending writes.

Tag groups require an admin API key. If not accessible, group reconciliation is skipped with a warning.

```bash
dsc -n tag push myforum tags.yaml          # dry-run: show plan
dsc tag push myforum tags.yaml             # apply upserts
dsc tag push myforum tags.yaml --prune     # full sync (deletes extras)
```

## dsc tag rename

Rename a tag, preserving every topic association. Discourse rewrites topic tag lists in-place rather than dropping and re-adding, so this is the safe alternative to editing a tag name in `tags.yaml` and running `dsc tag push` (which sees the old name as removed and the new name as added).

```bash
dsc tag rename myforum old-name new-name        # rename
dsc -n tag rename myforum old-name new-name     # dry-run
```

Aliases: `rn`.

Refuses to run when:

- the old tag does not exist on the server,
- a tag with the new name already exists (merging is not supported),
- the new name contains whitespace (Discourse tags are slug-style),
- old and new names are identical after trimming.

## Notes

- **Renames**: prefer `dsc tag rename` over editing the name in a pulled file. A name change in the file is indistinguishable from delete + create, which drops topic associations.
- Tag groups are admin-only; `pull` and `push` degrade gracefully when using a non-admin key.
- The desired tag set on push = the union of every `tags[].name` and every name listed under any group's `tags:`.

## Examples

```bash
# Pull, edit, push workflow
dsc tag pull myforum
$EDITOR tags.yaml
dsc -n tag push myforum tags.yaml   # preview
dsc tag push myforum tags.yaml      # apply

# Rename a tag preserving topic membership
dsc -n tag rename myforum bug defect    # preview
dsc tag rename myforum bug defect       # apply
```
