Ozone
Kotlin Multiplatform bindings for Bluesky
Install / Use
/learn @christiandeange/OzoneREADME
ozone
Overview
The Ozone project for the AT Protocol consists of several components:
- A Gradle plugin to compile AT Protocol schemas into usable Kotlin classes.
- Multiplatform APIs for the AT Protocol spec that can be used with any compatible service, including Bluesky Social.
- Supports Android, JVM, JavaScript, and iOS.
- APIs to authenticate via OAuth to a Personal Data Server (PDS).
- Supports Android, JVM, JavaScript, and iOS.
- APIs to connect to the Jetstream firehose for Bluesky Social.
- Supports Android, JVM, and JavaScript.
- Example client apps that demonstrate usage of those APIs.
Why "Ozone"?
O<sub>3</sub> exists at all levels in the ATmosphere.
No relation to the moderation tools also named Ozone.
Bluesky Social Bindings
Documentation is available at ozone.christian.sh.
Warning
🚧 🚧 🚧 Everything in here is very much a work-in-progress! The upstream schemas are still subject to breaking changes and may break at any moment if used in production code. Use at your own risk!
Java / Kotlin
// build.gradle[.kts]
dependencies {
api("sh.christian.ozone:bluesky:0.3.3")
}
Swift / Objective-C
In Xcode, select File > Add Packages and enter https://github.com/christiandeange/BlueskyAPI
OAuth Client
Documentation is available at ozone.christian.sh in the sh.christian.ozone.oauth package.
Java / Kotlin
// build.gradle[.kts]
dependencies {
api("sh.christian.ozone:oauth:0.3.3")
}
Jetstream Bindings
Documentation is available at ozone.christian.sh in the sh.christian.ozone.jetstream package.
Java / Kotlin
// build.gradle[.kts]
dependencies {
api("sh.christian.ozone:jetstream:0.3.3")
}
Gradle Plugin
In addition to shipping the lexicons that define the official Bluesky API, this project also includes a Gradle Plugin that allows you to bring your own lexicon definitions and generate any set of AT Protocol bindings from them.
// build.gradle[.kts]
plugins {
id("sh.christian.ozone.generator") version "0.3.3"
}
dependencies {
// This is where you have your schema files stored in your project.
lexicons(fileTree("lexicons") { include("**/*.json") })
// You can also depend directly on the published Bluesky lexicons instead.
lexicons("sh.christian.ozone:lexicons:2026.03.28")
}
lexicons {
// Determines the package name of generated supporting methods. Defaults to "sh.christian.ozone".
namespace.set("com.example.myapp")
// Configuration for how to handle unknown types and known values.
defaults {
// Determines whether to generate classes to encapsulate unknown types for union references. Defaults to false.
generateUnknownsForSealedTypes.set(true)
// Determines whether to generate classes to encapsulate unknown values for strings. Defaults to false.
generateUnknownsForEnums.set(true)
// Defines what type to use when the protocol has binary data inputs or outputs. Defaults to ByteArray.
binaryDataType.set(BinaryDataType.ByteArray)
}
// Generates an additional interface for the target schemas.
// This method can be called more than once to generate multiple API interfaces.
generateApi("BlueskyApi") {
// Determines the package name of the generated API. Defaults to "sh.christian.ozone".
packageName.set("com.example.myapp")
// Generates an additional class that implements this interface by sending corresponding
// XRPC requests to a provided host conforming to the AT Protocol.
// Inherits the same package name as the generated interface.
// NOTE: Responses are still read entirely into memory regardless of the binaryDataType
// specified in the default configuration. Streaming response types are unsupported
// at this time.
withKtorImplementation("XrpcBlueskyApi")
// Determines the return type for each generated API method. Defaults to Raw.
// - Raw: the raw data type
// - Result: Result<T>
// - Response: AtpResponse<T>
returnType.set(ApiReturnType.Result)
// Determines whether the generated methods should be marked as suspend functions.
// When generating a Ktor implementation as well, execution will block the current thread
// for non-suspending methods. Defaults to true.
suspending.set(true)
}
// File path where Kotlin source files will be written to. Defaults to "<project-dir>/build/generated/lexicons".
outputDirectory.set(project.layout.buildDirectory.dir("out"))
}
