Ozone
The Ozone module provides convenience methods for Ozone moderation tooling (tools.ozone.* endpoints). These are used by labeler operators and moderation teams to take actions on content and accounts.
All Ozone functions require a serviceDid parameter -- the DID of the Ozone moderation service. The proxy header is applied automatically; you do not need to configure it manually.
All examples use taskResult {}. See the Error Handling guide for details.
open FSharp.ATProto.Core
open FSharp.ATProto.Bluesky
open FSharp.ATProto.Syntax
Key Types
OzoneSubject
The target of a moderation action:
type OzoneSubject =
| Account of Did // an entire account
| Record of PostRef // a specific record (post, etc.)
ModerationAction
The action to perform:
Case |
Description |
|---|---|
|
Take down a subject permanently or temporarily |
|
Reverse a previous takedown |
|
Acknowledge a report |
|
Escalate for higher-level review |
|
Add or remove labels |
|
Add a comment to a subject |
|
Mute incoming reports on a subject |
|
Unmute incoming reports |
|
Mute incoming reports from a reporter |
|
Unmute a reporter |
|
Add or remove tags |
|
Resolve an appeal |
TeamRole
type TeamRole = Admin | Moderator | Triage | Verifier
TeamMember
type TeamMember =
{ Did : Did
Role : TeamRole
Disabled : bool
CreatedAt : DateTimeOffset option
UpdatedAt : DateTimeOffset option }
Moderation Events
Function |
Description |
|---|---|
|
Emit a moderation event on a subject |
|
Get a moderation event by ID |
|
Query moderation events with optional filters |
|
Query the moderation review queue |
|
Get detailed subject information |
Taking Down a Post and Adding a Label
taskResult {
let! agent = Bluesky.login "https://bsky.social" "mod-handle.bsky.social" "app-password"
// Take down a post
let! _ =
Ozone.emitEvent agent serviceDid
(OzoneSubject.Record offendingPostRef)
(ModerationAction.Takedown (Some "Violates community guidelines", None))
// Add a label to an account
let! _ =
Ozone.emitEvent agent serviceDid
(OzoneSubject.Account userDid)
(ModerationAction.Label (Some "Content warning", [ "nsfw" ], []))
// Reverse the takedown later
let! _ =
Ozone.emitEvent agent serviceDid
(OzoneSubject.Record offendingPostRef)
(ModerationAction.ReverseTakedown (Some "Reviewed and cleared"))
return ()
}
Repository Inspection
Function |
Description |
|---|---|
|
Get detailed moderation view for an account by DID |
|
Get detailed moderation view for a record by AT-URI |
|
Search accounts in the moderation system |
taskResult {
let! repoDetail = Ozone.getRepo agent serviceDid userDid
let! recordDetail = Ozone.getRecord agent serviceDid recordUri
let! searchResults = Ozone.searchRepos agent serviceDid "spam" (Some 10L) None
return ()
}
Team Management
Function |
Description |
|---|---|
|
List moderation team members |
|
Add a team member with a role |
|
Remove a team member |
|
Update a member's role or disabled status |
taskResult {
// Add a new moderator
let! _newMember = Ozone.addMember agent serviceDid newModeratorDid TeamRole.Moderator
// Promote to admin
let! _ = Ozone.updateMember agent serviceDid newModeratorDid (Some TeamRole.Admin) None
// List all team members
let! page = Ozone.listMembers agent serviceDid None None
for m in page.Items do
printfn "%s - %A" (Did.value m.Did) m.Role
}
Communication Templates
Templates for standardized moderation communications:
Function |
Description |
|---|---|
|
List all communication templates |
|
Create a new template |
|
Update an existing template |
|
Delete a template by ID |
taskResult {
let! template =
Ozone.createTemplate agent serviceDid
"Spam Warning"
"Your content was flagged as spam. Please review our community guidelines."
"Content Policy Notice"
printfn "Created template: %s" template.Id
// Update the template
let! _ = Ozone.updateTemplate agent serviceDid template.Id
(Some "Updated Spam Warning") None None None
// Delete it
do! Ozone.deleteTemplate agent serviceDid template.Id
}
namespace FSharp
--------------------
namespace Microsoft.FSharp
module AtpAgent from FSharp.ATProto.Core
<summary> Functions for creating and authenticating <see cref="AtpAgent" /> instances. </summary>
--------------------
type AtpAgent = { HttpClient: HttpClient mutable BaseUrl: Uri mutable Session: AtpSession option ExtraHeaders: (string * string) list AuthenticateRequest: (HttpRequestMessage -> unit) option RefreshAuthentication: (unit -> Task<Result<unit,XrpcError>>) option OnSessionChanged: (unit -> unit) option }
<summary> Client agent for communicating with an AT Protocol Personal Data Server (PDS). Holds the HTTP client, base URL, optional authenticated session, and extra headers. </summary>
<remarks> Create an agent with <see cref="AtpAgent.create" /> or <see cref="AtpAgent.createWithClient" />, then authenticate with <see cref="AtpAgent.login" />. The agent's <see cref="Session" /> field is mutable: it is updated automatically on login and token refresh. </remarks>
<example><code> let agent = AtpAgent.create "https://bsky.social" let! session = AtpAgent.login "my-handle.bsky.social" "app-password-here" agent </code></example>
module Did from FSharp.ATProto.Syntax
<summary> Functions for creating, validating, and extracting data from <see cref="Did" /> values. </summary>
--------------------
type Did = private | Did of string override ToString: unit -> string
<summary> A decentralized identifier (DID) as defined by the AT Protocol. DIDs are the primary stable identifier for accounts. Two methods are currently supported: <c>did:plc:</c> (hosted, managed by PLC directory) and <c>did:web:</c> (self-hosted, DNS-based). </summary>
<remarks> See the AT Protocol specification: https://atproto.com/specs/did and the W3C DID specification: https://www.w3.org/TR/did-core/ </remarks>
<summary> A reference to a specific version of a post record. Contains both the AT-URI (identifying the record) and the CID (identifying the exact version). Accepted by <c>like</c>, <c>repost</c>, and <c>replyTo</c>. </summary>
module AtUri from FSharp.ATProto.Syntax
<summary> Functions for creating, validating, and extracting data from <see cref="AtUri" /> values. </summary>
--------------------
type AtUri = private | AtUri of string override ToString: unit -> string
<summary> An AT-URI that identifies a resource in the AT Protocol network. AT-URIs use the scheme <c>at://</c> followed by an authority (DID or handle), an optional collection (NSID), and an optional record key. Format: <c>at://<authority>[/<collection>[/<rkey>]]</c>. Maximum length is 8192 characters. </summary>
<remarks> See the AT Protocol specification: https://atproto.com/specs/at-uri-scheme </remarks>
<summary> High-level convenience methods for common Bluesky operations: posting, replying, liking, reposting, following, blocking, uploading blobs, and deleting records. All methods require an authenticated <see cref="AtpAgent" />. </summary>
<summary> Convenience methods for Ozone moderation tooling (<c>tools.ozone.*</c> endpoints). Wraps the generated XRPC types with a simplified, type-safe API. <para> Ozone endpoints require the agent to be proxied to the moderation service. Pass the labeler/moderation service DID via the <c>serviceDid</c> parameter. The proxy header (<c>atproto-proxy: {did}#atproto_labeler</c>) is applied automatically -- callers do not need to configure proxy headers manually. </para></summary>
<summary> Emit a moderation event on a subject. This is the primary way to take moderation actions in Ozone: takedowns, labels, flags, acknowledgments, escalations, and more. </summary>
<param name="agent">An authenticated <see cref="AtpAgent" />.</param>
<param name="serviceDid">The DID of the Ozone moderation service to proxy to.</param>
<param name="subject">The subject of the moderation action (account or record).</param>
<param name="action">The moderation action to perform.</param>
<returns>The emitted moderation event view, or an <see cref="XrpcError" />.</returns>
<summary> The subject of an Ozone moderation action: either an account (by DID) or a record (by AT-URI + CID). </summary>
<summary> A type-safe union of moderation events that can be emitted via <c>Ozone.emitEvent</c>. Each case maps to the corresponding <c>tools.ozone.moderation.defs#modEvent*</c> type. </summary>
<summary> Take down a subject permanently or temporarily. </summary>
<summary> Add or remove labels on a subject. </summary>
<summary> Reverse a previous takedown action. </summary>
<summary> Get the detailed moderation view for a specific repo (account) by DID. </summary>
<param name="agent">An authenticated <see cref="AtpAgent" />.</param>
<param name="serviceDid">The DID of the Ozone moderation service.</param>
<param name="did">The DID of the account to look up.</param>
<returns>The detailed repo view, or an <see cref="XrpcError" />.</returns>
<summary> Get the detailed moderation view for a specific record by AT-URI. </summary>
<param name="agent">An authenticated <see cref="AtpAgent" />.</param>
<param name="serviceDid">The DID of the Ozone moderation service.</param>
<param name="uri">The AT-URI of the record to look up.</param>
<returns>The detailed record view, or an <see cref="XrpcError" />.</returns>
<summary> Search repos (accounts) in the moderation system by query string. </summary>
<param name="agent">An authenticated <see cref="AtpAgent" />.</param>
<param name="serviceDid">The DID of the Ozone moderation service.</param>
<param name="query">The search query string.</param>
<param name="limit">Maximum number of results to return.</param>
<param name="cursor">Pagination cursor from a previous response.</param>
<returns>A page of repo views, or an <see cref="XrpcError" />.</returns>
<summary> Add a new member to the Ozone moderation team. </summary>
<param name="agent">An authenticated <see cref="AtpAgent" />.</param>
<param name="serviceDid">The DID of the Ozone moderation service.</param>
<param name="memberDid">The DID of the user to add as a team member.</param>
<param name="role">The role to assign to the new member.</param>
<returns>The newly created team member, or an <see cref="XrpcError" />.</returns>
<summary> The role of a team member in an Ozone moderation service. </summary>
<summary> Update an existing team member's role or disabled status. </summary>
<param name="agent">An authenticated <see cref="AtpAgent" />.</param>
<param name="serviceDid">The DID of the Ozone moderation service.</param>
<param name="memberDid">The DID of the member to update.</param>
<param name="role">The new role for the member, or <c>None</c> to leave unchanged.</param>
<param name="disabled">Whether the member should be disabled, or <c>None</c> to leave unchanged.</param>
<returns>The updated team member, or an <see cref="XrpcError" />.</returns>
<summary> List the members of the Ozone moderation team. </summary>
<param name="agent">An authenticated <see cref="AtpAgent" />.</param>
<param name="serviceDid">The DID of the Ozone moderation service.</param>
<param name="limit">Maximum number of members to return.</param>
<param name="cursor">Pagination cursor from a previous response.</param>
<returns>A page of team members, or an <see cref="XrpcError" />.</returns>
<summary> Extract the string representation of a DID. </summary>
<param name="did">The DID to extract the value from.</param>
<returns>The full DID string (e.g. <c>"did:plc:z72i7hdynmk6r22z27h6tvur"</c>).</returns>
<summary> Create a new communication template. </summary>
<param name="agent">An authenticated <see cref="AtpAgent" />.</param>
<param name="serviceDid">The DID of the Ozone moderation service.</param>
<param name="name">The name of the template.</param>
<param name="contentMarkdown">The template content in Markdown format.</param>
<param name="subject">Optional subject line for the template.</param>
<returns>The newly created template, or an <see cref="XrpcError" />.</returns>
<summary> Update an existing communication template. </summary>
<param name="agent">An authenticated <see cref="AtpAgent" />.</param>
<param name="serviceDid">The DID of the Ozone moderation service.</param>
<param name="id">The ID of the template to update.</param>
<param name="name">New name, or <c>None</c> to leave unchanged.</param>
<param name="contentMarkdown">New content, or <c>None</c> to leave unchanged.</param>
<param name="subject">New subject, or <c>None</c> to leave unchanged.</param>
<param name="disabled">Whether to disable the template, or <c>None</c> to leave unchanged.</param>
<returns>The updated template, or an <see cref="XrpcError" />.</returns>
<summary> Delete a communication template by ID. </summary>
<param name="agent">An authenticated <see cref="AtpAgent" />.</param>
<param name="serviceDid">The DID of the Ozone moderation service.</param>
<param name="id">The ID of the template to delete.</param>
<returns><c>Ok ()</c> on success, or an <see cref="XrpcError" />.</returns>