Skip to content

client.tags

Bases: SyncResource

Sync project-tags namespace (client.tags).

list

list(project_id: UUID | str) -> ProjectTagList

The project's authoritative tag palette — every defined tag with its color/display and how many assets carry it (0 = defined but unused). A complete snapshot, not a cursor page.

Raises:

Type Description
NotFoundError

unknown project (PROJECT_NOT_FOUND).

ForbiddenError

caller is not a project member (AUTH_FORBIDDEN).

create

create(project_id: UUID | str, *, value: str, color: str | None = None, display: str | None = None) -> ProjectTag

Define a new tag in the palette (Manager+). A freshly defined tag has count=0 until it's applied.

Parameters:

Name Type Description Default
value str

the canonical tag value (no leading/trailing whitespace).

required
color str | None

#rrggbb hex hint (validated + lowercased server-side).

None
display str | None

optional display label.

None

Raises:

Type Description
ConflictError

the value already exists (NAME_TAKEN).

ForbiddenError

caller is not a project manager (AUTH_FORBIDDEN).

UnprocessableError

bad color hex / whitespace in value.

update

update(project_id: UUID | str, *, value: str, new_value: str | None = None, color: str | None = None, display: str | None = None) -> TagUpdateResult

Rename and/or recolor/redisplay a palette tag (Manager+). value identifies the existing tag; pass at least one of new_value/color/ display. Renaming rewrites every asset's tag array (dedup-merge if new_value already exists).

Raises:

Type Description
NotFoundError

value isn't defined in this project (UNCATEGORIZED).

ForbiddenError

caller is not a project manager (AUTH_FORBIDDEN).

UnprocessableError

bad color hex / whitespace in a value.

delete

delete(project_id: UUID | str, *, value: str) -> TagDeleteResult

Delete a tag project-wide (Manager+): remove it from every asset that carries it and drop it from the palette. Idempotent — deleting an unused tag returns assets_untagged=0. Returns a result body (200, not 204).

Raises:

Type Description
ForbiddenError

caller is not a project manager (AUTH_FORBIDDEN).

summary

summary(project_id: UUID | str, *, asset_ids: list[UUID | str] | None = None, filter: ProjectFilterParam | None = None, exclude_asset_ids: list[UUID | str] | None = None) -> TagSummary

Aggregate tag application across a target set (any project member). Pass EXACTLY ONE of asset_ids or filter (a ProjectFilter: status/assigned_to/tags/classes/annotated/…). exclude_asset_ids is filter-mode only.

Raises:

Type Description
PayloadTooLargeError

asset_ids exceeds 1000 (PAYLOAD_TOO_LARGE) — switch to a filter-mode call.

UnprocessableError

neither/both of asset_ids/filter, or excludes with asset_ids (VALIDATION_ERROR).

ForbiddenError

caller is not a project member (AUTH_FORBIDDEN).

batch_update

batch_update(project_id: UUID | str, *, asset_ids: list[UUID | str], tags_add: list[str] | None = None, tags_remove: list[str] | None = None) -> TagBatchResult

Sync dual-arm tag update over explicit asset_ids (≤1000; Manager+). Both arms apply atomically in one UPDATE. Returns inline per-id status. For larger/filter-driven selections use :meth:bulk_update.

Parameters:

Name Type Description Default
tags_add list[str] | None

tag values to add. At least one of tags_add/tags_remove must be non-empty.

None
tags_remove list[str] | None

tag values to remove.

None

Raises:

Type Description
PayloadTooLargeError

asset_ids exceeds 1000 (PAYLOAD_TOO_LARGE).

BadRequestError

an added tag isn't in the palette and the project is free_form=false (BAD_REQUEST).

UnprocessableError

both arms empty, or an empty tag value (VALIDATION_ERROR).

ForbiddenError

caller is not a project manager (AUTH_FORBIDDEN).

bulk_update

bulk_update(project_id: UUID | str, *, tags_add: list[str] | None = None, tags_remove: list[str] | None = None, asset_ids: list[UUID | str] | None = None, filter: ProjectFilterParam | None = None, exclude_asset_ids: list[UUID | str] | None = None, idempotency_key: str | None = None) -> JobHandle

Kick off an async dual-arm tag update (Manager+); returns a :class:JobHandle (202). Both arms apply atomically per worker batch. Pass EXACTLY ONE of asset_ids or filter; exclude_asset_ids is filter-mode only. At least one of tags_add/tags_remove non-empty.

Raises:

Type Description
BadRequestError

an added tag isn't in the palette and the project is free_form=false (BAD_REQUEST) — checked before the job enqueues.

ConflictError

idempotency key reused with a different body (IDEMPOTENCY_REPLAY).

RateLimitError

per-tenant active-job cap reached (JOB_PER_TENANT_CAP).

UnprocessableError

bad selection / both arms empty (VALIDATION_ERROR).

ForbiddenError

caller is not a project manager (AUTH_FORBIDDEN).

Response models

Models returned by client.tags methods (fields, types, and what each means).

Project tag-palette models (ADR-0058 / ADR-0050).

A project's tags form an authoritative palette (project.tag_config.allowed_tags) layered over the per-asset project_asset_state.tags arrays. These models cover the palette CRUD reads plus the tag-application aggregates (summary) and the sync batch-update envelope. The async bulk-update-tags kickoff returns a Job (see types.jobs), not a model here.

Response models only (extra="allow"); request bodies are built as dicts in the resource. Nothing here depends on another type module — every field is a primitive.

ProjectTag

Bases: BaseModel

One tag in the project's authoritative palette: its definition (value + optional color/display) plus current usage count.

ProjectTagList

Bases: BaseModel

The project's full tag palette (a complete snapshot, not a cursor page). Iterate .tags for the entries.

TagUpdateResult

Bases: BaseModel

Result of a palette-tag update: the final entry + how many asset rows had their tag array rewritten (rename only; 0 for a pure recolor/redisplay).

TagDeleteResult

Bases: BaseModel

Result of deleting a tag project-wide: untag-all count + whether it was also dropped from the palette.

TagSummaryItem

Bases: BaseModel

One tag value + how many assets in the target set carry it. Tri-state checkbox logic: count == total checked, 0 < count < total indeterminate, absent from the list unchecked.

TagSummary

Bases: BaseModel

Aggregate tag application across a target set: total in-scope assets + per-tag counts. Tags applied to zero in-scope assets are simply absent.

TagBatchResultItem

Bases: BaseModel

Per-asset outcome of a sync batch_update. skipped = not in the project or already in the desired tag state.

TagBatchResult

Bases: BaseModel

Sync batch-op envelope (ADR-0041): total == updated + skipped and len(results) == total.