Guides

Moderation

Models emit signals. Named presets map scores to allow, review, or block. The sidecar is not in the npm package.

Models emit signals. The engine policy maps scores to allow | review | block. Scores are numeric thresholds. Detoxify does not understand idiom or sarcasm.

Supported modalities:

  • Text: Detoxify (sidecar)
  • Images: NudeNet plus Falconsai NSFW classifier (sidecar)

Audio and video are not moderated. They still persist if media config allows them.

When moderation is enabled for a type, the message is stored with moderationStatus=pending. Public status is none | pending | allowed | review | blocked | failed. Pending, held-for-review, blocked, and failed content is redacted from recipients. Decision block records audit rows and emits message.blocked without delivering the body.

The sidecar is a separate deployable. It is not part of @gozwire/core.

Compose defaults to fixture scores so Docker starts without multi-gigabyte PyTorch weights. That is for local wiring. Production inference uses the documented models.

Presets

Named presets are lenient, balanced, strict, and custom. Defaults: text lenient, image strict. Overlapping labels require review < block. Completions stamp processing-time policyVersion (text:{textPreset}|image:{imagePreset}).

Runtime changes go through configuration.updateModeration and return a public-safe DTO (toPublicModerationConfig) only. Never sidecar tokens or URLs. The demo Configuration page can change enablement and presets. It must not leak credentials.

gozwire.configuration.updateModeration({
  enabled?,
  textEnabled?,
  imageEnabled?,
  textPreset?,
  imagePreset?,
  textPolicy?,
  imagePolicy?,
});

Hosts that want the previous text map set textPreset: "balanced".

gozwire.moderation.list({
  actorId,
  limit?,
  before?,
  status?,
  decision?,
  modality?,
}): Promise<{ jobs: ModerationJobListItem[]; nextCursor: string | null }>;

list requires actorId. There is no OFFSET. Reviewer IDs and review-delivery mode are engine config.