Skip to content

plexctl group

Synopsis

plexctl group is the operator surface for the per-Domain ReBAC Group aggregate and its GroupMembership child collection. It wraps the typed /v1/admin/groups and /v1/admin/groups/{id}/members endpoints so an operator can manage Groups (create, list, get, update, delete) and their memberships (add, list, remove) without hand-rolling curl calls.

The command is split into two cohesive blocks: the CRUD block on the Group aggregate itself, and the member subcommand block that operates on the membership child collection. The wire-shape decisions (source enum, principal-kind discriminator, the immutable slug contract on update) are documented next to each subcommand below; the canonical Group context lives in ../../contexts/identity/groups.md.

Invocation

text
plexctl group <subcommand> [flags]
plexctl group member <subcommand> [flags]

The eight subcommands are enumerated below. Every subcommand is a private cobra constructor; flags are validated at parse time so an invalid --source or --kind never reaches the wire.

plexctl group create

Creates a Group inside a Domain. The handler enforces the manual / idp XOR on the aggregate; the CLI rejects a --source value that is not in the OpenAPI enum at flag-parse time so a typo surfaces as exit 2 instead of a 400 round-trip.

plexctl group list

Lists Groups in a Domain. Supports keyset pagination via --cursor and an opt-in --all flag that walks every page until the next_cursor field is empty. The --all accumulator is capped at 100 000 items as defence-in-depth against a runaway server.

plexctl group get

Returns a single Group by UUID.

plexctl group update

Updates a Group's mutable fields. Only display_name is settable — the slug is frozen after creation per the OpenAPI contract; an attempt to rename through update is rejected by the schema before reaching the aggregate.

plexctl group delete

Deletes a Group. Requires the persistent --yes flag — a destructive op behind a single typo of the group id is unacceptable, so the RunE refuses to call the API without explicit confirmation .

plexctl group member add

Adds a principal (user, service_identity, or group) to a Group. The --source of the membership MUST match the parent Group's source (both manual or both idp); the server enforces the parity but the CLI surface keeps the contract visible.

plexctl group member list

Lists every membership of a Group.

plexctl group member remove

Removes a principal from a Group. The --kind discriminator is required because the group_memberships table uses an XOR on the principal columns — the server needs the kind to target the correct column, and reading the OpenAPI param annotation guarantees the CLI mirrors the wire contract.

Flags

plexctl group create

FlagTypeRequiredDefaultDescription
--domainUUIDyesOwning Domain UUID.
--slugstringyesURL-safe identifier unique within the Domain. Frozen after creation.
--display-namestringyesHuman-friendly Group name.
--sourceenumyesProvenance: manual | idp.
--idp-bindingUUIDconditionalIdP binding UUID. Required when --source=idp (the aggregate enforces the XOR).
--idp-claim-valuestringconditionalVerbatim IdP claim value. Required when --source=idp.

plexctl group list

FlagTypeRequiredDefaultDescription
--domainUUIDyesOwning Domain UUID.
--limitintnoserver defaultMaximum items per page. 0 lets the server pick.
--cursorstringnoContinuation token from a previous call's next_cursor. Mutually exclusive with --all.
--allboolnofalseFollow next_cursor until exhausted (capped at 100 000 items).

plexctl group get

FlagTypeRequiredDefaultDescription
--idUUIDyesGroup UUID.

plexctl group update

FlagTypeRequiredDefaultDescription
--idUUIDyesGroup UUID.
--display-namestringyesNew human-friendly Group name.

plexctl group delete

FlagTypeRequiredDefaultDescription
--idUUIDyesGroup UUID.
--yes (persistent)boolyesfalseRequired confirmation for the destructive operation.

plexctl group member add

FlagTypeRequiredDefaultDescription
--groupUUIDyesGroup UUID.
--principalUUIDyesPrincipal UUID (user / service identity / nested group).
--kindenumyesPrincipal kind: user | service_identity | group.
--sourceenumyesMembership provenance: manual | idp (must match the parent Group).

plexctl group member list

FlagTypeRequiredDefaultDescription
--groupUUIDyesGroup UUID.

plexctl group member remove

FlagTypeRequiredDefaultDescription
--groupUUIDyesGroup UUID.
--principalUUIDyesPrincipal UUID.
--kindenumyesPrincipal kind: user | service_identity | group. The repo targets the correct XOR column on group_memberships via this discriminator.

Persistent flags inherited from root

--server, --profile, --token-file, --output, --yes, --reveal-secrets. The --yes flag is consumed by delete; the others apply unchanged. See plexctl.md for the canonical list.

Exit codes

plexctl collapses every failure into the taxonomy below; the single source of truth is exitCodeFor in ../../../cmd/plexctl/app.go.

CodeReachableMeaning
0yesThe API returned the expected status (201 for create / member add, 200 for list / get / update, 204 for delete / member remove).
1yesRuntime / API error: transport failure, unexpected status code, or a malformed response body.
2yesFlag-parse / misconfiguration: missing required flag, malformed UUID, unknown --source / --kind value, or delete without --yes.
3yesMissing or insecure credentials, or 401 Unauthorized from the API.
4yesPermission denied: 403 Forbidden from the API (e.g. the operator lacks domain:manage).
64noNot reachable — group is fully implemented and never returns *NotImplementedError.

Examples

Create an idp-sourced Group

shell
export PLEXSPHERE_URL="${PLEXSPHERE_URL:-https://localhost:8080}"

plexctl group create \
  --server "${PLEXSPHERE_URL}" \
  --domain          0190a8b8-a0c0-7a0a-8a0a-a0a0a0a0a0a0 \
  --slug            sre-oncall \
  --display-name    "SRE On-Call" \
  --source          idp \
  --idp-binding     0190a8b8-a0c0-7a0a-8a0a-a0a0a0a0a0b0 \
  --idp-claim-value "groups:sre-oncall"

Page through every Group in a Domain

shell
plexctl group list \
  --server "${PLEXSPHERE_URL}" \
  --domain 0190a8b8-a0c0-7a0a-8a0a-a0a0a0a0a0a0 \
  --all \
  --output json

Add a service identity to a manual Group

shell
plexctl group member add \
  --server    "${PLEXSPHERE_URL}" \
  --group     0190a8b8-a0c0-7a0a-8a0a-a0a0a0a0a0c0 \
  --principal 0190a8b8-a0c0-7a0a-8a0a-a0a0a0a0a0d0 \
  --kind      service_identity \
  --source    manual

Permission denied (exit 4)

shell
plexctl group delete \
  --server "${PLEXSPHERE_URL}" \
  --id     0190a8b8-a0c0-7a0a-8a0a-a0a0a0a0a0c0 \
  --yes
# stderr: plexctl: 403 Forbidden: insufficient_relation (need domain:manage)
echo $?  # 4

The 403 is decoded by output.DecodeProblem and routed to exit 4 through the typed *output.APIError path in exitCodeFor.

Cross-references

  • ../../../api/openapi/plexsphere-v1.yamlPostAdminGroup, GetAdminGroupList, GetAdminGroupByID, PatchAdminGroup, DeleteAdminGroupByID, PostAdminGroupMember, GetAdminGroupMembers, DeleteAdminGroupMember operation definitions and the GroupResponse, GroupListResponse, GroupMembershipResponse, GroupMembershipListResponse schemas.
  • ../../contexts/identity/groups.md — bounded-context reference for the Group aggregate, the manual / idp XOR, the membership state machine, and the audit contract.
  • ../../../cmd/plexctl/commands/group.go — source of truth for the cobra command, flag wiring, the --all cap, and the table projection.