Repository: sugyan/atrium (language: rust)

Issue:
Suggestion: Change code writer
Hey,
you folks could use a set of crates to assemble the generated code in a more structured manner:
* Use https://crates.io/crates/quote to write the individual pieces of code
* Use https://crates.io/crates/syn and https://crates.io/crates/proc-macro2 to have structs for pieces of `Ident`s for the struct names etc. and `TokenStream`
* Use https://crates.io/crates/prettyplease to pretty print the whole shebang

The basic idea:
1. Assemble lots of small `TokenStream`s to a large one
2. Convert `TokenStream` to `&str` using https://docs.rs/proc-macro2/1.0.56/proc_macro2/struct.TokenStream.html#method.to_string
3. Pipe the generated string through https://docs.rs/syn/2.0.15/syn/fn.parse_file.html to generate a https://docs.rs/syn/2.0.15/syn/struct.File.html
4. Pipe https://docs.rs/syn/2.0.15/syn/struct.File.html through https://docs.rs/prettyplease/0.2.4/prettyplease/fn.unparse.html to have a pretty printed `String`

Given this approach of having a `TokenStream` you get proper error messages, when something is not a legit AST token and you could add your own pretty printer, ...

If the idea is not clear enough, please ask :)


Discussion / hints:
Thanks for the great suggestion!
I've never implemented a code writer before, and I honestly thought I'd start with something that worked anyway, so I did it pretty crudely. I was going to rewrite it later to make it look better...

I'll try to rewrite it based on your suggestion!
I don't know if this is "theeee" correct way to do it, but you get a free code formatter with it :D
Hmm. Here's a quick one. I'm currently working on the same problem: 
> having a proper Rust version of the AT protocol

If you would love to have someone helping you working on `atrium`, I would be glad to help. I have some suggestions and some new code (axum server code to create a PDS), I would love to contribute.

If you like the idea, we could have a quick talk at Discord or via E-Mail.
Thank you for your suggestion for contributions.
I personally am inclined to implement them at a leisurely pace while pondering the design on my own, but I should probably ask for help in moving the protocol implementation OSS project forward.
If you send me pull requests, I will do my best to review and test them.

Fix patch:
diff --git a/atrium-api/src/app.rs b/atrium-api/src/app.rs
index a64127e3..a7fc2a10 100644
--- a/atrium-api/src/app.rs
+++ b/atrium-api/src/app.rs
@@ -1,2 +1,2 @@
-// This file is generated by atrium-codegen. Do not edit.
+// This file is generated by atrium-codegen. DO NOT EDIT.
 pub mod bsky;
diff --git a/atrium-api/src/app/bsky.rs b/atrium-api/src/app/bsky.rs
index c1c1089f..b5d03d34 100644
--- a/atrium-api/src/app/bsky.rs
+++ b/atrium-api/src/app/bsky.rs
@@ -1,4 +1,4 @@
-// This file is generated by atrium-codegen. Do not edit.
+// This file is generated by atrium-codegen. DO NOT EDIT.
 pub mod actor;
 pub mod embed;
 pub mod feed;
diff --git a/atrium-api/src/app/bsky/actor.rs b/atrium-api/src/app/bsky/actor.rs
index 85ab52ba..96605a41 100644
--- a/atrium-api/src/app/bsky/actor.rs
+++ b/atrium-api/src/app/bsky/actor.rs
@@ -1,4 +1,4 @@
-// This file is generated by atrium-codegen. Do not edit.
+// This file is generated by atrium-codegen. DO NOT EDIT.
 pub mod defs;
 pub mod get_profile;
 pub mod get_profiles;
diff --git a/atrium-api/src/app/bsky/actor/defs.rs b/atrium-api/src/app/bsky/actor/defs.rs
index 165413f9..b9bcb9c1 100644
--- a/atrium-api/src/app/bsky/actor/defs.rs
+++ b/atrium-api/src/app/bsky/actor/defs.rs
@@ -1,9 +1,8 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `app.bsky.actor.defs` namespace.
-//! A reference to an actor in the network.
-
-// app.bsky.actor.defs#profileView
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `app.bsky.actor.defs` namespace."]
+#![doc = "A reference to an actor in the network."]
+#[doc = "`app.bsky.actor.defs#profileView`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct ProfileView {
     #[serde(skip_serializing_if = "Option::is_none")]
@@ -21,9 +20,8 @@ pub struct ProfileView {
     #[serde(skip_serializing_if = "Option::is_none")]
     pub viewer: Option<ViewerState>,
 }
-
-// app.bsky.actor.defs#profileViewBasic
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[doc = "`app.bsky.actor.defs#profileViewBasic`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct ProfileViewBasic {
     #[serde(skip_serializing_if = "Option::is_none")]
@@ -37,9 +35,8 @@ pub struct ProfileViewBasic {
     #[serde(skip_serializing_if = "Option::is_none")]
     pub viewer: Option<ViewerState>,
 }
-
-// app.bsky.actor.defs#profileViewDetailed
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[doc = "`app.bsky.actor.defs#profileViewDetailed`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct ProfileViewDetailed {
     #[serde(skip_serializing_if = "Option::is_none")]
@@ -65,9 +62,8 @@ pub struct ProfileViewDetailed {
     #[serde(skip_serializing_if = "Option::is_none")]
     pub viewer: Option<ViewerState>,
 }
-
-// app.bsky.actor.defs#viewerState
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[doc = "`app.bsky.actor.defs#viewerState`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct ViewerState {
     #[serde(skip_serializing_if = "Option::is_none")]
diff --git a/atrium-api/src/app/bsky/actor/get_profile.rs b/atrium-api/src/app/bsky/actor/get_profile.rs
index cc4cfaa8..fb361896 100644
--- a/atrium-api/src/app/bsky/actor/get_profile.rs
+++ b/atrium-api/src/app/bsky/actor/get_profile.rs
@@ -1,6 +1,6 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `app.bsky.actor.getProfile` namespace.
-
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `app.bsky.actor.getProfile` namespace."]
+#[doc = "`app.bsky.actor.getProfile`"]
 #[async_trait::async_trait]
 pub trait GetProfile: crate::xrpc::XrpcClient {
     async fn get_profile(&self, params: Parameters) -> Result<Output, Box<dyn std::error::Error>> {
@@ -16,15 +16,12 @@ pub trait GetProfile: crate::xrpc::XrpcClient {
         serde_json::from_slice(&body).map_err(|e| e.into())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Parameters {
     pub actor: String,
 }
-
 pub type Output = crate::app::bsky::actor::defs::ProfileViewDetailed;
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {}
diff --git a/atrium-api/src/app/bsky/actor/get_profiles.rs b/atrium-api/src/app/bsky/actor/get_profiles.rs
index 9dbcc68d..3d01524f 100644
--- a/atrium-api/src/app/bsky/actor/get_profiles.rs
+++ b/atrium-api/src/app/bsky/actor/get_profiles.rs
@@ -1,6 +1,6 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `app.bsky.actor.getProfiles` namespace.
-
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `app.bsky.actor.getProfiles` namespace."]
+#[doc = "`app.bsky.actor.getProfiles`"]
 #[async_trait::async_trait]
 pub trait GetProfiles: crate::xrpc::XrpcClient {
     async fn get_profiles(&self, params: Parameters) -> Result<Output, Box<dyn std::error::Error>> {
@@ -16,19 +16,16 @@ pub trait GetProfiles: crate::xrpc::XrpcClient {
         serde_json::from_slice(&body).map_err(|e| e.into())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Parameters {
     pub actors: Vec<String>,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Output {
     pub profiles: Vec<crate::app::bsky::actor::defs::ProfileViewDetailed>,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {}
diff --git a/atrium-api/src/app/bsky/actor/get_suggestions.rs b/atrium-api/src/app/bsky/actor/get_suggestions.rs
index b66fe3d9..4c7ce9a1 100644
--- a/atrium-api/src/app/bsky/actor/get_suggestions.rs
+++ b/atrium-api/src/app/bsky/actor/get_suggestions.rs
@@ -1,7 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `app.bsky.actor.getSuggestions` namespace.
-
-/// Get a list of actors suggested for following. Used in discovery UIs.
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `app.bsky.actor.getSuggestions` namespace."]
+#[doc = "`app.bsky.actor.getSuggestions`"]
+#[doc = "Get a list of actors suggested for following. Used in discovery UIs."]
 #[async_trait::async_trait]
 pub trait GetSuggestions: crate::xrpc::XrpcClient {
     async fn get_suggestions(
@@ -20,8 +20,7 @@ pub trait GetSuggestions: crate::xrpc::XrpcClient {
         serde_json::from_slice(&body).map_err(|e| e.into())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Parameters {
     #[serde(skip_serializing_if = "Option::is_none")]
@@ -29,15 +28,13 @@ pub struct Parameters {
     #[serde(skip_serializing_if = "Option::is_none")]
     pub limit: Option<i32>,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Output {
     pub actors: Vec<crate::app::bsky::actor::defs::ProfileView>,
     #[serde(skip_serializing_if = "Option::is_none")]
     pub cursor: Option<String>,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {}
diff --git a/atrium-api/src/app/bsky/actor/profile.rs b/atrium-api/src/app/bsky/actor/profile.rs
index 65fd65d0..91c5edb5 100644
--- a/atrium-api/src/app/bsky/actor/profile.rs
+++ b/atrium-api/src/app/bsky/actor/profile.rs
@@ -1,8 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `app.bsky.actor.profile` namespace.
-
-// app.bsky.actor.profile
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `app.bsky.actor.profile` namespace."]
+#[doc = "`app.bsky.actor.profile`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Record {
     #[serde(skip_serializing_if = "Option::is_none")]
diff --git a/atrium-api/src/app/bsky/actor/search_actors.rs b/atrium-api/src/app/bsky/actor/search_actors.rs
index fb46b884..86cedc40 100644
--- a/atrium-api/src/app/bsky/actor/search_actors.rs
+++ b/atrium-api/src/app/bsky/actor/search_actors.rs
@@ -1,7 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `app.bsky.actor.searchActors` namespace.
-
-/// Find actors matching search criteria.
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `app.bsky.actor.searchActors` namespace."]
+#[doc = "`app.bsky.actor.searchActors`"]
+#[doc = "Find actors matching search criteria."]
 #[async_trait::async_trait]
 pub trait SearchActors: crate::xrpc::XrpcClient {
     async fn search_actors(
@@ -20,8 +20,7 @@ pub trait SearchActors: crate::xrpc::XrpcClient {
         serde_json::from_slice(&body).map_err(|e| e.into())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Parameters {
     #[serde(skip_serializing_if = "Option::is_none")]
@@ -31,15 +30,13 @@ pub struct Parameters {
     #[serde(skip_serializing_if = "Option::is_none")]
     pub term: Option<String>,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Output {
     pub actors: Vec<crate::app::bsky::actor::defs::ProfileView>,
     #[serde(skip_serializing_if = "Option::is_none")]
     pub cursor: Option<String>,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {}
diff --git a/atrium-api/src/app/bsky/actor/search_actors_typeahead.rs b/atrium-api/src/app/bsky/actor/search_actors_typeahead.rs
index 51aab714..0b2c4665 100644
--- a/atrium-api/src/app/bsky/actor/search_actors_typeahead.rs
+++ b/atrium-api/src/app/bsky/actor/search_actors_typeahead.rs
@@ -1,7 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `app.bsky.actor.searchActorsTypeahead` namespace.
-
-/// Find actor suggestions for a search term.
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `app.bsky.actor.searchActorsTypeahead` namespace."]
+#[doc = "`app.bsky.actor.searchActorsTypeahead`"]
+#[doc = "Find actor suggestions for a search term."]
 #[async_trait::async_trait]
 pub trait SearchActorsTypeahead: crate::xrpc::XrpcClient {
     async fn search_actors_typeahead(
@@ -20,8 +20,7 @@ pub trait SearchActorsTypeahead: crate::xrpc::XrpcClient {
         serde_json::from_slice(&body).map_err(|e| e.into())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Parameters {
     #[serde(skip_serializing_if = "Option::is_none")]
@@ -29,13 +28,11 @@ pub struct Parameters {
     #[serde(skip_serializing_if = "Option::is_none")]
     pub term: Option<String>,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Output {
     pub actors: Vec<crate::app::bsky::actor::defs::ProfileViewBasic>,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {}
diff --git a/atrium-api/src/app/bsky/embed.rs b/atrium-api/src/app/bsky/embed.rs
index dabf3e4f..8c5d474d 100644
--- a/atrium-api/src/app/bsky/embed.rs
+++ b/atrium-api/src/app/bsky/embed.rs
@@ -1,4 +1,4 @@
-// This file is generated by atrium-codegen. Do not edit.
+// This file is generated by atrium-codegen. DO NOT EDIT.
 pub mod external;
 pub mod images;
 pub mod record;
diff --git a/atrium-api/src/app/bsky/embed/external.rs b/atrium-api/src/app/bsky/embed/external.rs
index 178d1607..25cd826d 100644
--- a/atrium-api/src/app/bsky/embed/external.rs
+++ b/atrium-api/src/app/bsky/embed/external.rs
@@ -1,16 +1,14 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `app.bsky.embed.external` namespace.
-//! A representation of some externally linked content, embedded in another form of content
-
-// app.bsky.embed.external
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `app.bsky.embed.external` namespace."]
+#![doc = "A representation of some externally linked content, embedded in another form of content"]
+#[doc = "`app.bsky.embed.external`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Main {
     pub external: External,
 }
-
-// app.bsky.embed.external#external
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[doc = "`app.bsky.embed.external#external`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct External {
     pub description: String,
@@ -19,16 +17,14 @@ pub struct External {
     pub title: String,
     pub uri: String,
 }
-
-// app.bsky.embed.external#view
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[doc = "`app.bsky.embed.external#view`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct View {
     pub external: ViewExternal,
 }
-
-// app.bsky.embed.external#viewExternal
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[doc = "`app.bsky.embed.external#viewExternal`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct ViewExternal {
     pub description: String,
diff --git a/atrium-api/src/app/bsky/embed/images.rs b/atrium-api/src/app/bsky/embed/images.rs
index 49990eca..ecdd15a0 100644
--- a/atrium-api/src/app/bsky/embed/images.rs
+++ b/atrium-api/src/app/bsky/embed/images.rs
@@ -1,31 +1,27 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `app.bsky.embed.images` namespace.
-//! A set of images embedded in some other form of content
-
-// app.bsky.embed.images
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `app.bsky.embed.images` namespace."]
+#![doc = "A set of images embedded in some other form of content"]
+#[doc = "`app.bsky.embed.images`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Main {
     pub images: Vec<Image>,
 }
-
-// app.bsky.embed.images#image
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[doc = "`app.bsky.embed.images#image`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Image {
     pub alt: String,
     pub image: crate::blob::BlobRef,
 }
-
-// app.bsky.embed.images#view
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[doc = "`app.bsky.embed.images#view`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct View {
     pub images: Vec<ViewImage>,
 }
-
-// app.bsky.embed.images#viewImage
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[doc = "`app.bsky.embed.images#viewImage`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct ViewImage {
     pub alt: String,
diff --git a/atrium-api/src/app/bsky/embed/record.rs b/atrium-api/src/app/bsky/embed/record.rs
index fbeb4f80..998a1440 100644
--- a/atrium-api/src/app/bsky/embed/record.rs
+++ b/atrium-api/src/app/bsky/embed/record.rs
@@ -1,52 +1,45 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `app.bsky.embed.record` namespace.
-//! A representation of a record embedded in another form of content
-
-// app.bsky.embed.record
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `app.bsky.embed.record` namespace."]
+#![doc = "A representation of a record embedded in another form of content"]
+#[doc = "`app.bsky.embed.record`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Main {
     pub record: crate::com::atproto::repo::strong_ref::Main,
 }
-
-// app.bsky.embed.record#view
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[doc = "`app.bsky.embed.record#view`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct View {
     pub record: Box<ViewRecordEnum>,
 }
-
-// app.bsky.embed.record#viewBlocked
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[doc = "`app.bsky.embed.record#viewBlocked`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct ViewBlocked {
     pub uri: String,
 }
-
-// app.bsky.embed.record#viewNotFound
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[doc = "`app.bsky.embed.record#viewNotFound`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct ViewNotFound {
     pub uri: String,
 }
-
-// app.bsky.embed.record#viewRecord
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[doc = "`app.bsky.embed.record#viewRecord`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct ViewRecord {
     pub author: crate::app::bsky::actor::defs::ProfileViewBasic,
     pub cid: String,
     #[serde(skip_serializing_if = "Option::is_none")]
-    pub embeds: Option<Vec<ViewRecordEmbedsItem>>,
+    pub embeds: Option<Vec<Box<ViewRecordEmbedsItem>>>,
     pub indexed_at: String,
     #[serde(skip_serializing_if = "Option::is_none")]
     pub labels: Option<Vec<crate::com::atproto::label::defs::Label>>,
     pub uri: String,
     pub value: crate::records::Record,
 }
-
-#[allow(clippy::large_enum_variant)]
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "$type")]
 pub enum ViewRecordEmbedsItem {
     #[serde(rename = "app.bsky.embed.images#view")]
@@ -58,9 +51,7 @@ pub enum ViewRecordEmbedsItem {
     #[serde(rename = "app.bsky.embed.recordWithMedia#view")]
     AppBskyEmbedRecordWithMediaView(crate::app::bsky::embed::record_with_media::View),
 }
-
-#[allow(clippy::large_enum_variant)]
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "$type")]
 pub enum ViewRecordEnum {
     #[serde(rename = "app.bsky.embed.record#viewRecord")]
diff --git a/atrium-api/src/app/bsky/embed/record_with_media.rs b/atrium-api/src/app/bsky/embed/record_with_media.rs
index a6cf1bc1..6a1cb5af 100644
--- a/atrium-api/src/app/bsky/embed/record_with_media.rs
+++ b/atrium-api/src/app/bsky/embed/record_with_media.rs
@@ -1,25 +1,21 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `app.bsky.embed.recordWithMedia` namespace.
-//! A representation of a record embedded in another form of content, alongside other compatible embeds
-
-// app.bsky.embed.recordWithMedia
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `app.bsky.embed.recordWithMedia` namespace."]
+#![doc = "A representation of a record embedded in another form of content, alongside other compatible embeds"]
+#[doc = "`app.bsky.embed.recordWithMedia`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Main {
     pub media: Box<MainMediaEnum>,
     pub record: crate::app::bsky::embed::record::Main,
 }
-
-// app.bsky.embed.recordWithMedia#view
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[doc = "`app.bsky.embed.recordWithMedia#view`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct View {
     pub media: Box<ViewMediaEnum>,
     pub record: crate::app::bsky::embed::record::View,
 }
-
-#[allow(clippy::large_enum_variant)]
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "$type")]
 pub enum MainMediaEnum {
     #[serde(rename = "app.bsky.embed.images")]
@@ -27,9 +23,7 @@ pub enum MainMediaEnum {
     #[serde(rename = "app.bsky.embed.external")]
     AppBskyEmbedExternalMain(crate::app::bsky::embed::external::Main),
 }
-
-#[allow(clippy::large_enum_variant)]
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "$type")]
 pub enum ViewMediaEnum {
     #[serde(rename = "app.bsky.embed.images#view")]
diff --git a/atrium-api/src/app/bsky/feed.rs b/atrium-api/src/app/bsky/feed.rs
index f14b2ac0..dffe9ab2 100644
--- a/atrium-api/src/app/bsky/feed.rs
+++ b/atrium-api/src/app/bsky/feed.rs
@@ -1,4 +1,4 @@
-// This file is generated by atrium-codegen. Do not edit.
+// This file is generated by atrium-codegen. DO NOT EDIT.
 pub mod defs;
 pub mod get_author_feed;
 pub mod get_likes;
diff --git a/atrium-api/src/app/bsky/feed/defs.rs b/atrium-api/src/app/bsky/feed/defs.rs
index 42136276..2aa60262 100644
--- a/atrium-api/src/app/bsky/feed/defs.rs
+++ b/atrium-api/src/app/bsky/feed/defs.rs
@@ -1,16 +1,14 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `app.bsky.feed.defs` namespace.
-
-// app.bsky.feed.defs#blockedPost
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `app.bsky.feed.defs` namespace."]
+#[doc = "`app.bsky.feed.defs#blockedPost`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct BlockedPost {
     pub blocked: bool,
     pub uri: String,
 }
-
-// app.bsky.feed.defs#feedViewPost
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[doc = "`app.bsky.feed.defs#feedViewPost`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct FeedViewPost {
     pub post: crate::app::bsky::feed::defs::PostView,
@@ -19,17 +17,15 @@ pub struct FeedViewPost {
     #[serde(skip_serializing_if = "Option::is_none")]
     pub reply: Option<ReplyRef>,
 }
-
-// app.bsky.feed.defs#notFoundPost
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[doc = "`app.bsky.feed.defs#notFoundPost`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct NotFoundPost {
     pub not_found: bool,
     pub uri: String,
 }
-
-// app.bsky.feed.defs#postView
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[doc = "`app.bsky.feed.defs#postView`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct PostView {
     pub author: crate::app::bsky::actor::defs::ProfileViewBasic,
@@ -50,36 +46,32 @@ pub struct PostView {
     #[serde(skip_serializing_if = "Option::is_none")]
     pub viewer: Option<ViewerState>,
 }
-
-// app.bsky.feed.defs#reasonRepost
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[doc = "`app.bsky.feed.defs#reasonRepost`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct ReasonRepost {
     pub by: crate::app::bsky::actor::defs::ProfileViewBasic,
     pub indexed_at: String,
 }
-
-// app.bsky.feed.defs#replyRef
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[doc = "`app.bsky.feed.defs#replyRef`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct ReplyRef {
     pub parent: crate::app::bsky::feed::defs::PostView,
     pub root: crate::app::bsky::feed::defs::PostView,
 }
-
-// app.bsky.feed.defs#threadViewPost
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[doc = "`app.bsky.feed.defs#threadViewPost`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct ThreadViewPost {
     #[serde(skip_serializing_if = "Option::is_none")]
     pub parent: Option<Box<ThreadViewPostParentEnum>>,
     pub post: PostView,
     #[serde(skip_serializing_if = "Option::is_none")]
-    pub replies: Option<Vec<ThreadViewPostRepliesItem>>,
+    pub replies: Option<Vec<Box<ThreadViewPostRepliesItem>>>,
 }
-
-// app.bsky.feed.defs#viewerState
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[doc = "`app.bsky.feed.defs#viewerState`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct ViewerState {
     #[serde(skip_serializing_if = "Option::is_none")]
@@ -87,17 +79,13 @@ pub struct ViewerState {
     #[serde(skip_serializing_if = "Option::is_none")]
     pub repost: Option<String>,
 }
-
-#[allow(clippy::large_enum_variant)]
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "$type")]
 pub enum FeedViewPostReasonEnum {
     #[serde(rename = "app.bsky.feed.defs#reasonRepost")]
     ReasonRepost(ReasonRepost),
 }
-
-#[allow(clippy::large_enum_variant)]
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "$type")]
 pub enum PostViewEmbedEnum {
     #[serde(rename = "app.bsky.embed.images#view")]
@@ -109,9 +97,7 @@ pub enum PostViewEmbedEnum {
     #[serde(rename = "app.bsky.embed.recordWithMedia#view")]
     AppBskyEmbedRecordWithMediaView(crate::app::bsky::embed::record_with_media::View),
 }
-
-#[allow(clippy::large_enum_variant)]
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "$type")]
 pub enum ThreadViewPostParentEnum {
     #[serde(rename = "app.bsky.feed.defs#threadViewPost")]
@@ -121,9 +107,7 @@ pub enum ThreadViewPostParentEnum {
     #[serde(rename = "app.bsky.feed.defs#blockedPost")]
     BlockedPost(BlockedPost),
 }
-
-#[allow(clippy::large_enum_variant)]
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "$type")]
 pub enum ThreadViewPostRepliesItem {
     #[serde(rename = "app.bsky.feed.defs#threadViewPost")]
diff --git a/atrium-api/src/app/bsky/feed/get_author_feed.rs b/atrium-api/src/app/bsky/feed/get_author_feed.rs
index c31f2a29..40eabec4 100644
--- a/atrium-api/src/app/bsky/feed/get_author_feed.rs
+++ b/atrium-api/src/app/bsky/feed/get_author_feed.rs
@@ -1,7 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `app.bsky.feed.getAuthorFeed` namespace.
-
-/// A view of an actor's feed.
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `app.bsky.feed.getAuthorFeed` namespace."]
+#[doc = "`app.bsky.feed.getAuthorFeed`"]
+#[doc = "A view of an actor's feed."]
 #[async_trait::async_trait]
 pub trait GetAuthorFeed: crate::xrpc::XrpcClient {
     async fn get_author_feed(
@@ -20,8 +20,7 @@ pub trait GetAuthorFeed: crate::xrpc::XrpcClient {
         serde_json::from_slice(&body).map_err(|e| e.into())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Parameters {
     pub actor: String,
@@ -30,16 +29,14 @@ pub struct Parameters {
     #[serde(skip_serializing_if = "Option::is_none")]
     pub limit: Option<i32>,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Output {
     #[serde(skip_serializing_if = "Option::is_none")]
     pub cursor: Option<String>,
     pub feed: Vec<crate::app::bsky::feed::defs::FeedViewPost>,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {
     BlockedActor(Option<String>),
diff --git a/atrium-api/src/app/bsky/feed/get_likes.rs b/atrium-api/src/app/bsky/feed/get_likes.rs
index 2c9f1837..ceffd90d 100644
--- a/atrium-api/src/app/bsky/feed/get_likes.rs
+++ b/atrium-api/src/app/bsky/feed/get_likes.rs
@@ -1,6 +1,6 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `app.bsky.feed.getLikes` namespace.
-
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `app.bsky.feed.getLikes` namespace."]
+#[doc = "`app.bsky.feed.getLikes`"]
 #[async_trait::async_trait]
 pub trait GetLikes: crate::xrpc::XrpcClient {
     async fn get_likes(&self, params: Parameters) -> Result<Output, Box<dyn std::error::Error>> {
@@ -16,8 +16,7 @@ pub trait GetLikes: crate::xrpc::XrpcClient {
         serde_json::from_slice(&body).map_err(|e| e.into())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Parameters {
     #[serde(skip_serializing_if = "Option::is_none")]
@@ -28,8 +27,7 @@ pub struct Parameters {
     pub limit: Option<i32>,
     pub uri: String,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Output {
     #[serde(skip_serializing_if = "Option::is_none")]
@@ -39,13 +37,11 @@ pub struct Output {
     pub likes: Vec<Like>,
     pub uri: String,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {}
-
-// app.bsky.feed.getLikes#like
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[doc = "`app.bsky.feed.getLikes#like`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Like {
     pub actor: crate::app::bsky::actor::defs::ProfileView,
diff --git a/atrium-api/src/app/bsky/feed/get_post_thread.rs b/atrium-api/src/app/bsky/feed/get_post_thread.rs
index 7f2c57c1..548cd134 100644
--- a/atrium-api/src/app/bsky/feed/get_post_thread.rs
+++ b/atrium-api/src/app/bsky/feed/get_post_thread.rs
@@ -1,6 +1,6 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `app.bsky.feed.getPostThread` namespace.
-
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `app.bsky.feed.getPostThread` namespace."]
+#[doc = "`app.bsky.feed.getPostThread`"]
 #[async_trait::async_trait]
 pub trait GetPostThread: crate::xrpc::XrpcClient {
     async fn get_post_thread(
@@ -19,29 +19,24 @@ pub trait GetPostThread: crate::xrpc::XrpcClient {
         serde_json::from_slice(&body).map_err(|e| e.into())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Parameters {
     #[serde(skip_serializing_if = "Option::is_none")]
     pub depth: Option<i32>,
     pub uri: String,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Output {
     pub thread: Box<OutputThreadEnum>,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {
     NotFound(Option<String>),
 }
-
-#[allow(clippy::large_enum_variant)]
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "$type")]
 pub enum OutputThreadEnum {
     #[serde(rename = "app.bsky.feed.defs#threadViewPost")]
diff --git a/atrium-api/src/app/bsky/feed/get_posts.rs b/atrium-api/src/app/bsky/feed/get_posts.rs
index 22f12d20..d0a779f6 100644
--- a/atrium-api/src/app/bsky/feed/get_posts.rs
+++ b/atrium-api/src/app/bsky/feed/get_posts.rs
@@ -1,7 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `app.bsky.feed.getPosts` namespace.
-
-/// A view of an actor's feed.
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `app.bsky.feed.getPosts` namespace."]
+#[doc = "`app.bsky.feed.getPosts`"]
+#[doc = "A view of an actor's feed."]
 #[async_trait::async_trait]
 pub trait GetPosts: crate::xrpc::XrpcClient {
     async fn get_posts(&self, params: Parameters) -> Result<Output, Box<dyn std::error::Error>> {
@@ -17,19 +17,16 @@ pub trait GetPosts: crate::xrpc::XrpcClient {
         serde_json::from_slice(&body).map_err(|e| e.into())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Parameters {
     pub uris: Vec<String>,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Output {
     pub posts: Vec<crate::app::bsky::feed::defs::PostView>,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {}
diff --git a/atrium-api/src/app/bsky/feed/get_reposted_by.rs b/atrium-api/src/app/bsky/feed/get_reposted_by.rs
index 12028f30..84309564 100644
--- a/atrium-api/src/app/bsky/feed/get_reposted_by.rs
+++ b/atrium-api/src/app/bsky/feed/get_reposted_by.rs
@@ -1,6 +1,6 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `app.bsky.feed.getRepostedBy` namespace.
-
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `app.bsky.feed.getRepostedBy` namespace."]
+#[doc = "`app.bsky.feed.getRepostedBy`"]
 #[async_trait::async_trait]
 pub trait GetRepostedBy: crate::xrpc::XrpcClient {
     async fn get_reposted_by(
@@ -19,8 +19,7 @@ pub trait GetRepostedBy: crate::xrpc::XrpcClient {
         serde_json::from_slice(&body).map_err(|e| e.into())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Parameters {
     #[serde(skip_serializing_if = "Option::is_none")]
@@ -31,8 +30,7 @@ pub struct Parameters {
     pub limit: Option<i32>,
     pub uri: String,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Output {
     #[serde(skip_serializing_if = "Option::is_none")]
@@ -42,7 +40,6 @@ pub struct Output {
     pub reposted_by: Vec<crate::app::bsky::actor::defs::ProfileView>,
     pub uri: String,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {}
diff --git a/atrium-api/src/app/bsky/feed/get_timeline.rs b/atrium-api/src/app/bsky/feed/get_timeline.rs
index 6cdb14b4..550281ce 100644
--- a/atrium-api/src/app/bsky/feed/get_timeline.rs
+++ b/atrium-api/src/app/bsky/feed/get_timeline.rs
@@ -1,7 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `app.bsky.feed.getTimeline` namespace.
-
-/// A view of the user's home timeline.
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `app.bsky.feed.getTimeline` namespace."]
+#[doc = "`app.bsky.feed.getTimeline`"]
+#[doc = "A view of the user's home timeline."]
 #[async_trait::async_trait]
 pub trait GetTimeline: crate::xrpc::XrpcClient {
     async fn get_timeline(&self, params: Parameters) -> Result<Output, Box<dyn std::error::Error>> {
@@ -17,8 +17,7 @@ pub trait GetTimeline: crate::xrpc::XrpcClient {
         serde_json::from_slice(&body).map_err(|e| e.into())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Parameters {
     #[serde(skip_serializing_if = "Option::is_none")]
@@ -28,15 +27,13 @@ pub struct Parameters {
     #[serde(skip_serializing_if = "Option::is_none")]
     pub limit: Option<i32>,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Output {
     #[serde(skip_serializing_if = "Option::is_none")]
     pub cursor: Option<String>,
     pub feed: Vec<crate::app::bsky::feed::defs::FeedViewPost>,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {}
diff --git a/atrium-api/src/app/bsky/feed/like.rs b/atrium-api/src/app/bsky/feed/like.rs
index 9370c647..7f5f80e8 100644
--- a/atrium-api/src/app/bsky/feed/like.rs
+++ b/atrium-api/src/app/bsky/feed/like.rs
@@ -1,8 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `app.bsky.feed.like` namespace.
-
-// app.bsky.feed.like
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `app.bsky.feed.like` namespace."]
+#[doc = "`app.bsky.feed.like`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Record {
     pub created_at: String,
diff --git a/atrium-api/src/app/bsky/feed/post.rs b/atrium-api/src/app/bsky/feed/post.rs
index c9d6faa4..1d364b76 100644
--- a/atrium-api/src/app/bsky/feed/post.rs
+++ b/atrium-api/src/app/bsky/feed/post.rs
@@ -1,14 +1,13 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `app.bsky.feed.post` namespace.
-
-// app.bsky.feed.post
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `app.bsky.feed.post` namespace."]
+#[doc = "`app.bsky.feed.post`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Record {
     pub created_at: String,
     #[serde(skip_serializing_if = "Option::is_none")]
     pub embed: Option<Box<RecordEmbedEnum>>,
-    /// Deprecated: replaced by app.bsky.richtext.facet.
+    #[doc = "Deprecated: replaced by app.bsky.richtext.facet."]
     #[serde(skip_serializing_if = "Option::is_none")]
     pub entities: Option<Vec<Entity>>,
     #[serde(skip_serializing_if = "Option::is_none")]
@@ -17,37 +16,32 @@ pub struct Record {
     pub reply: Option<ReplyRef>,
     pub text: String,
 }
-
-// app.bsky.feed.post#entity
-/// Deprecated: use facets instead.
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[doc = "`app.bsky.feed.post#entity`"]
+#[doc = "Deprecated: use facets instead."]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Entity {
     pub index: TextSlice,
-    /// Expected values are 'mention' and 'link'.
+    #[doc = "Expected values are 'mention' and 'link'."]
     pub r#type: String,
     pub value: String,
 }
-
-// app.bsky.feed.post#replyRef
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[doc = "`app.bsky.feed.post#replyRef`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct ReplyRef {
     pub parent: crate::com::atproto::repo::strong_ref::Main,
     pub root: crate::com::atproto::repo::strong_ref::Main,
 }
-
-// app.bsky.feed.post#textSlice
-/// Deprecated. Use app.bsky.richtext instead -- A text segment. Start is inclusive, end is exclusive. Indices are for utf16-encoded strings.
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[doc = "`app.bsky.feed.post#textSlice`"]
+#[doc = "Deprecated. Use app.bsky.richtext instead -- A text segment. Start is inclusive, end is exclusive. Indices are for utf16-encoded strings."]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct TextSlice {
     pub end: i32,
     pub start: i32,
 }
-
-#[allow(clippy::large_enum_variant)]
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "$type")]
 pub enum RecordEmbedEnum {
     #[serde(rename = "app.bsky.embed.images")]
diff --git a/atrium-api/src/app/bsky/feed/repost.rs b/atrium-api/src/app/bsky/feed/repost.rs
index 6344ee9e..9bcd572b 100644
--- a/atrium-api/src/app/bsky/feed/repost.rs
+++ b/atrium-api/src/app/bsky/feed/repost.rs
@@ -1,8 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `app.bsky.feed.repost` namespace.
-
-// app.bsky.feed.repost
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `app.bsky.feed.repost` namespace."]
+#[doc = "`app.bsky.feed.repost`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Record {
     pub created_at: String,
diff --git a/atrium-api/src/app/bsky/graph.rs b/atrium-api/src/app/bsky/graph.rs
index f98413d0..cc33b612 100644
--- a/atrium-api/src/app/bsky/graph.rs
+++ b/atrium-api/src/app/bsky/graph.rs
@@ -1,4 +1,4 @@
-// This file is generated by atrium-codegen. Do not edit.
+// This file is generated by atrium-codegen. DO NOT EDIT.
 pub mod block;
 pub mod follow;
 pub mod get_blocks;
diff --git a/atrium-api/src/app/bsky/graph/block.rs b/atrium-api/src/app/bsky/graph/block.rs
index 9b0a1c4f..7c4f4d9b 100644
--- a/atrium-api/src/app/bsky/graph/block.rs
+++ b/atrium-api/src/app/bsky/graph/block.rs
@@ -1,9 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `app.bsky.graph.block` namespace.
-
-// app.bsky.graph.block
-/// A block.
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `app.bsky.graph.block` namespace."]
+#[doc = "`app.bsky.graph.block`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Record {
     pub created_at: String,
diff --git a/atrium-api/src/app/bsky/graph/follow.rs b/atrium-api/src/app/bsky/graph/follow.rs
index a4b081b2..97ed0df8 100644
--- a/atrium-api/src/app/bsky/graph/follow.rs
+++ b/atrium-api/src/app/bsky/graph/follow.rs
@@ -1,9 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `app.bsky.graph.follow` namespace.
-
-// app.bsky.graph.follow
-/// A social follow.
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `app.bsky.graph.follow` namespace."]
+#[doc = "`app.bsky.graph.follow`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Record {
     pub created_at: String,
diff --git a/atrium-api/src/app/bsky/graph/get_blocks.rs b/atrium-api/src/app/bsky/graph/get_blocks.rs
index 540211fe..5ffc17d9 100644
--- a/atrium-api/src/app/bsky/graph/get_blocks.rs
+++ b/atrium-api/src/app/bsky/graph/get_blocks.rs
@@ -1,7 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `app.bsky.graph.getBlocks` namespace.
-
-/// Who is the requester's account blocking?
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `app.bsky.graph.getBlocks` namespace."]
+#[doc = "`app.bsky.graph.getBlocks`"]
+#[doc = "Who is the requester's account blocking?"]
 #[async_trait::async_trait]
 pub trait GetBlocks: crate::xrpc::XrpcClient {
     async fn get_blocks(&self, params: Parameters) -> Result<Output, Box<dyn std::error::Error>> {
@@ -17,8 +17,7 @@ pub trait GetBlocks: crate::xrpc::XrpcClient {
         serde_json::from_slice(&body).map_err(|e| e.into())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Parameters {
     #[serde(skip_serializing_if = "Option::is_none")]
@@ -26,15 +25,13 @@ pub struct Parameters {
     #[serde(skip_serializing_if = "Option::is_none")]
     pub limit: Option<i32>,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Output {
     pub blocks: Vec<crate::app::bsky::actor::defs::ProfileView>,
     #[serde(skip_serializing_if = "Option::is_none")]
     pub cursor: Option<String>,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {}
diff --git a/atrium-api/src/app/bsky/graph/get_followers.rs b/atrium-api/src/app/bsky/graph/get_followers.rs
index 76916c49..8b34bae9 100644
--- a/atrium-api/src/app/bsky/graph/get_followers.rs
+++ b/atrium-api/src/app/bsky/graph/get_followers.rs
@@ -1,7 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `app.bsky.graph.getFollowers` namespace.
-
-/// Who is following an actor?
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `app.bsky.graph.getFollowers` namespace."]
+#[doc = "`app.bsky.graph.getFollowers`"]
+#[doc = "Who is following an actor?"]
 #[async_trait::async_trait]
 pub trait GetFollowers: crate::xrpc::XrpcClient {
     async fn get_followers(
@@ -20,8 +20,7 @@ pub trait GetFollowers: crate::xrpc::XrpcClient {
         serde_json::from_slice(&body).map_err(|e| e.into())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Parameters {
     pub actor: String,
@@ -30,8 +29,7 @@ pub struct Parameters {
     #[serde(skip_serializing_if = "Option::is_none")]
     pub limit: Option<i32>,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Output {
     #[serde(skip_serializing_if = "Option::is_none")]
@@ -39,7 +37,6 @@ pub struct Output {
     pub followers: Vec<crate::app::bsky::actor::defs::ProfileView>,
     pub subject: crate::app::bsky::actor::defs::ProfileView,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {}
diff --git a/atrium-api/src/app/bsky/graph/get_follows.rs b/atrium-api/src/app/bsky/graph/get_follows.rs
index 9bf636d2..5a09ed63 100644
--- a/atrium-api/src/app/bsky/graph/get_follows.rs
+++ b/atrium-api/src/app/bsky/graph/get_follows.rs
@@ -1,7 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `app.bsky.graph.getFollows` namespace.
-
-/// Who is an actor following?
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `app.bsky.graph.getFollows` namespace."]
+#[doc = "`app.bsky.graph.getFollows`"]
+#[doc = "Who is an actor following?"]
 #[async_trait::async_trait]
 pub trait GetFollows: crate::xrpc::XrpcClient {
     async fn get_follows(&self, params: Parameters) -> Result<Output, Box<dyn std::error::Error>> {
@@ -17,8 +17,7 @@ pub trait GetFollows: crate::xrpc::XrpcClient {
         serde_json::from_slice(&body).map_err(|e| e.into())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Parameters {
     pub actor: String,
@@ -27,8 +26,7 @@ pub struct Parameters {
     #[serde(skip_serializing_if = "Option::is_none")]
     pub limit: Option<i32>,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Output {
     #[serde(skip_serializing_if = "Option::is_none")]
@@ -36,7 +34,6 @@ pub struct Output {
     pub follows: Vec<crate::app::bsky::actor::defs::ProfileView>,
     pub subject: crate::app::bsky::actor::defs::ProfileView,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {}
diff --git a/atrium-api/src/app/bsky/graph/get_mutes.rs b/atrium-api/src/app/bsky/graph/get_mutes.rs
index f1f597a3..b665f6c3 100644
--- a/atrium-api/src/app/bsky/graph/get_mutes.rs
+++ b/atrium-api/src/app/bsky/graph/get_mutes.rs
@@ -1,7 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `app.bsky.graph.getMutes` namespace.
-
-/// Who does the viewer mute?
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `app.bsky.graph.getMutes` namespace."]
+#[doc = "`app.bsky.graph.getMutes`"]
+#[doc = "Who does the viewer mute?"]
 #[async_trait::async_trait]
 pub trait GetMutes: crate::xrpc::XrpcClient {
     async fn get_mutes(&self, params: Parameters) -> Result<Output, Box<dyn std::error::Error>> {
@@ -17,8 +17,7 @@ pub trait GetMutes: crate::xrpc::XrpcClient {
         serde_json::from_slice(&body).map_err(|e| e.into())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Parameters {
     #[serde(skip_serializing_if = "Option::is_none")]
@@ -26,15 +25,13 @@ pub struct Parameters {
     #[serde(skip_serializing_if = "Option::is_none")]
     pub limit: Option<i32>,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Output {
     #[serde(skip_serializing_if = "Option::is_none")]
     pub cursor: Option<String>,
     pub mutes: Vec<crate::app::bsky::actor::defs::ProfileView>,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {}
diff --git a/atrium-api/src/app/bsky/graph/mute_actor.rs b/atrium-api/src/app/bsky/graph/mute_actor.rs
index 2dd24605..1c86b665 100644
--- a/atrium-api/src/app/bsky/graph/mute_actor.rs
+++ b/atrium-api/src/app/bsky/graph/mute_actor.rs
@@ -1,7 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `app.bsky.graph.muteActor` namespace.
-
-/// Mute an actor by did or handle.
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `app.bsky.graph.muteActor` namespace."]
+#[doc = "`app.bsky.graph.muteActor`"]
+#[doc = "Mute an actor by did or handle."]
 #[async_trait::async_trait]
 pub trait MuteActor: crate::xrpc::XrpcClient {
     async fn mute_actor(&self, input: Input) -> Result<(), Box<dyn std::error::Error>> {
@@ -17,13 +17,11 @@ pub trait MuteActor: crate::xrpc::XrpcClient {
         Ok(())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Input {
     pub actor: String,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {}
diff --git a/atrium-api/src/app/bsky/graph/unmute_actor.rs b/atrium-api/src/app/bsky/graph/unmute_actor.rs
index ca9db0ab..97aed58f 100644
--- a/atrium-api/src/app/bsky/graph/unmute_actor.rs
+++ b/atrium-api/src/app/bsky/graph/unmute_actor.rs
@@ -1,7 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `app.bsky.graph.unmuteActor` namespace.
-
-/// Unmute an actor by did or handle.
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `app.bsky.graph.unmuteActor` namespace."]
+#[doc = "`app.bsky.graph.unmuteActor`"]
+#[doc = "Unmute an actor by did or handle."]
 #[async_trait::async_trait]
 pub trait UnmuteActor: crate::xrpc::XrpcClient {
     async fn unmute_actor(&self, input: Input) -> Result<(), Box<dyn std::error::Error>> {
@@ -17,13 +17,11 @@ pub trait UnmuteActor: crate::xrpc::XrpcClient {
         Ok(())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Input {
     pub actor: String,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {}
diff --git a/atrium-api/src/app/bsky/notification.rs b/atrium-api/src/app/bsky/notification.rs
index d8c846c8..d4343745 100644
--- a/atrium-api/src/app/bsky/notification.rs
+++ b/atrium-api/src/app/bsky/notification.rs
@@ -1,4 +1,4 @@
-// This file is generated by atrium-codegen. Do not edit.
+// This file is generated by atrium-codegen. DO NOT EDIT.
 pub mod get_unread_count;
 pub mod list_notifications;
 pub mod update_seen;
diff --git a/atrium-api/src/app/bsky/notification/get_unread_count.rs b/atrium-api/src/app/bsky/notification/get_unread_count.rs
index 79859982..e42fd432 100644
--- a/atrium-api/src/app/bsky/notification/get_unread_count.rs
+++ b/atrium-api/src/app/bsky/notification/get_unread_count.rs
@@ -1,6 +1,6 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `app.bsky.notification.getUnreadCount` namespace.
-
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `app.bsky.notification.getUnreadCount` namespace."]
+#[doc = "`app.bsky.notification.getUnreadCount`"]
 #[async_trait::async_trait]
 pub trait GetUnreadCount: crate::xrpc::XrpcClient {
     async fn get_unread_count(
@@ -19,20 +19,17 @@ pub trait GetUnreadCount: crate::xrpc::XrpcClient {
         serde_json::from_slice(&body).map_err(|e| e.into())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Parameters {
     #[serde(skip_serializing_if = "Option::is_none")]
     pub seen_at: Option<String>,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Output {
     pub count: i32,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {}
diff --git a/atrium-api/src/app/bsky/notification/list_notifications.rs b/atrium-api/src/app/bsky/notification/list_notifications.rs
index d40741ed..4abd3b8a 100644
--- a/atrium-api/src/app/bsky/notification/list_notifications.rs
+++ b/atrium-api/src/app/bsky/notification/list_notifications.rs
@@ -1,6 +1,6 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `app.bsky.notification.listNotifications` namespace.
-
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `app.bsky.notification.listNotifications` namespace."]
+#[doc = "`app.bsky.notification.listNotifications`"]
 #[async_trait::async_trait]
 pub trait ListNotifications: crate::xrpc::XrpcClient {
     async fn list_notifications(
@@ -19,8 +19,7 @@ pub trait ListNotifications: crate::xrpc::XrpcClient {
         serde_json::from_slice(&body).map_err(|e| e.into())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Parameters {
     #[serde(skip_serializing_if = "Option::is_none")]
@@ -30,21 +29,18 @@ pub struct Parameters {
     #[serde(skip_serializing_if = "Option::is_none")]
     pub seen_at: Option<String>,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Output {
     #[serde(skip_serializing_if = "Option::is_none")]
     pub cursor: Option<String>,
     pub notifications: Vec<Notification>,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {}
-
-// app.bsky.notification.listNotifications#notification
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[doc = "`app.bsky.notification.listNotifications#notification`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Notification {
     pub author: crate::app::bsky::actor::defs::ProfileView,
@@ -53,7 +49,7 @@ pub struct Notification {
     pub is_read: bool,
     #[serde(skip_serializing_if = "Option::is_none")]
     pub labels: Option<Vec<crate::com::atproto::label::defs::Label>>,
-    /// Expected values are 'like', 'repost', 'follow', 'mention', 'reply', and 'quote'.
+    #[doc = "Expected values are 'like', 'repost', 'follow', 'mention', 'reply', and 'quote'."]
     pub reason: String,
     #[serde(skip_serializing_if = "Option::is_none")]
     pub reason_subject: Option<String>,
diff --git a/atrium-api/src/app/bsky/notification/update_seen.rs b/atrium-api/src/app/bsky/notification/update_seen.rs
index 97d4cc03..e0942ce9 100644
--- a/atrium-api/src/app/bsky/notification/update_seen.rs
+++ b/atrium-api/src/app/bsky/notification/update_seen.rs
@@ -1,7 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `app.bsky.notification.updateSeen` namespace.
-
-/// Notify server that the user has seen notifications.
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `app.bsky.notification.updateSeen` namespace."]
+#[doc = "`app.bsky.notification.updateSeen`"]
+#[doc = "Notify server that the user has seen notifications."]
 #[async_trait::async_trait]
 pub trait UpdateSeen: crate::xrpc::XrpcClient {
     async fn update_seen(&self, input: Input) -> Result<(), Box<dyn std::error::Error>> {
@@ -17,13 +17,11 @@ pub trait UpdateSeen: crate::xrpc::XrpcClient {
         Ok(())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Input {
     pub seen_at: String,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {}
diff --git a/atrium-api/src/app/bsky/richtext.rs b/atrium-api/src/app/bsky/richtext.rs
index a5e85822..9f2beb0c 100644
--- a/atrium-api/src/app/bsky/richtext.rs
+++ b/atrium-api/src/app/bsky/richtext.rs
@@ -1,2 +1,2 @@
-// This file is generated by atrium-codegen. Do not edit.
+// This file is generated by atrium-codegen. DO NOT EDIT.
 pub mod facet;
diff --git a/atrium-api/src/app/bsky/richtext/facet.rs b/atrium-api/src/app/bsky/richtext/facet.rs
index 509d366d..ce0bd46b 100644
--- a/atrium-api/src/app/bsky/richtext/facet.rs
+++ b/atrium-api/src/app/bsky/richtext/facet.rs
@@ -1,41 +1,35 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `app.bsky.richtext.facet` namespace.
-
-// app.bsky.richtext.facet
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `app.bsky.richtext.facet` namespace."]
+#[doc = "`app.bsky.richtext.facet`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Main {
-    pub features: Vec<MainFeaturesItem>,
+    pub features: Vec<Box<MainFeaturesItem>>,
     pub index: ByteSlice,
 }
-
-// app.bsky.richtext.facet#byteSlice
-/// A text segment. Start is inclusive, end is exclusive. Indices are for utf8-encoded strings.
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[doc = "`app.bsky.richtext.facet#byteSlice`"]
+#[doc = "A text segment. Start is inclusive, end is exclusive. Indices are for utf8-encoded strings."]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct ByteSlice {
     pub byte_end: i32,
     pub byte_start: i32,
 }
-
-// app.bsky.richtext.facet#link
-/// A facet feature for links.
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[doc = "`app.bsky.richtext.facet#link`"]
+#[doc = "A facet feature for links."]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Link {
     pub uri: String,
 }
-
-// app.bsky.richtext.facet#mention
-/// A facet feature for actor mentions.
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[doc = "`app.bsky.richtext.facet#mention`"]
+#[doc = "A facet feature for actor mentions."]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Mention {
     pub did: String,
 }
-
-#[allow(clippy::large_enum_variant)]
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "$type")]
 pub enum MainFeaturesItem {
     #[serde(rename = "app.bsky.richtext.facet#mention")]
diff --git a/atrium-api/src/app/bsky/unspecced.rs b/atrium-api/src/app/bsky/unspecced.rs
index b44a66ec..3a34d589 100644
--- a/atrium-api/src/app/bsky/unspecced.rs
+++ b/atrium-api/src/app/bsky/unspecced.rs
@@ -1,2 +1,2 @@
-// This file is generated by atrium-codegen. Do not edit.
+// This file is generated by atrium-codegen. DO NOT EDIT.
 pub mod get_popular;
diff --git a/atrium-api/src/app/bsky/unspecced/get_popular.rs b/atrium-api/src/app/bsky/unspecced/get_popular.rs
index d99e1a05..e105335e 100644
--- a/atrium-api/src/app/bsky/unspecced/get_popular.rs
+++ b/atrium-api/src/app/bsky/unspecced/get_popular.rs
@@ -1,7 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `app.bsky.unspecced.getPopular` namespace.
-
-/// An unspecced view of globally popular items
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `app.bsky.unspecced.getPopular` namespace."]
+#[doc = "`app.bsky.unspecced.getPopular`"]
+#[doc = "An unspecced view of globally popular items"]
 #[async_trait::async_trait]
 pub trait GetPopular: crate::xrpc::XrpcClient {
     async fn get_popular(&self, params: Parameters) -> Result<Output, Box<dyn std::error::Error>> {
@@ -17,8 +17,7 @@ pub trait GetPopular: crate::xrpc::XrpcClient {
         serde_json::from_slice(&body).map_err(|e| e.into())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Parameters {
     #[serde(skip_serializing_if = "Option::is_none")]
@@ -28,15 +27,13 @@ pub struct Parameters {
     #[serde(skip_serializing_if = "Option::is_none")]
     pub limit: Option<i32>,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Output {
     #[serde(skip_serializing_if = "Option::is_none")]
     pub cursor: Option<String>,
     pub feed: Vec<crate::app::bsky::feed::defs::FeedViewPost>,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {}
diff --git a/atrium-api/src/com.rs b/atrium-api/src/com.rs
index b9732799..cfec005f 100644
--- a/atrium-api/src/com.rs
+++ b/atrium-api/src/com.rs
@@ -1,2 +1,2 @@
-// This file is generated by atrium-codegen. Do not edit.
+// This file is generated by atrium-codegen. DO NOT EDIT.
 pub mod atproto;
diff --git a/atrium-api/src/com/atproto.rs b/atrium-api/src/com/atproto.rs
index 54a7e3f0..d1b5bddd 100644
--- a/atrium-api/src/com/atproto.rs
+++ b/atrium-api/src/com/atproto.rs
@@ -1,4 +1,4 @@
-// This file is generated by atrium-codegen. Do not edit.
+// This file is generated by atrium-codegen. DO NOT EDIT.
 pub mod admin;
 pub mod identity;
 pub mod label;
diff --git a/atrium-api/src/com/atproto/admin.rs b/atrium-api/src/com/atproto/admin.rs
index 83e8c3f7..b707ac30 100644
--- a/atrium-api/src/com/atproto/admin.rs
+++ b/atrium-api/src/com/atproto/admin.rs
@@ -1,4 +1,4 @@
-// This file is generated by atrium-codegen. Do not edit.
+// This file is generated by atrium-codegen. DO NOT EDIT.
 pub mod defs;
 pub mod disable_invite_codes;
 pub mod get_invite_codes;
diff --git a/atrium-api/src/com/atproto/admin/defs.rs b/atrium-api/src/com/atproto/admin/defs.rs
index b859d65c..6a6fd1ff 100644
--- a/atrium-api/src/com/atproto/admin/defs.rs
+++ b/atrium-api/src/com/atproto/admin/defs.rs
@@ -1,25 +1,20 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `com.atproto.admin.defs` namespace.
-
-// com.atproto.admin.defs#acknowledge
-/// Moderation action type: Acknowledge. Indicates that the content was reviewed and not considered to violate PDS rules.
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `com.atproto.admin.defs` namespace."]
+#[doc = "`com.atproto.admin.defs#acknowledge`"]
+#[doc = "Moderation action type: Acknowledge. Indicates that the content was reviewed and not considered to violate PDS rules."]
 pub struct Acknowledge;
-
-// com.atproto.admin.defs#actionReversal
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[doc = "`com.atproto.admin.defs#actionReversal`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct ActionReversal {
     pub created_at: String,
     pub created_by: String,
     pub reason: String,
 }
-
-// com.atproto.admin.defs#actionType
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
-pub struct ActionType;
-
-// com.atproto.admin.defs#actionView
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[doc = "`com.atproto.admin.defs#actionType`"]
+pub type ActionType = String;
+#[doc = "`com.atproto.admin.defs#actionView`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct ActionView {
     pub action: ActionType,
@@ -37,17 +32,15 @@ pub struct ActionView {
     pub subject: Box<ActionViewSubjectEnum>,
     pub subject_blob_cids: Vec<String>,
 }
-
-// com.atproto.admin.defs#actionViewCurrent
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[doc = "`com.atproto.admin.defs#actionViewCurrent`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct ActionViewCurrent {
     pub action: ActionType,
     pub id: i32,
 }
-
-// com.atproto.admin.defs#actionViewDetail
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[doc = "`com.atproto.admin.defs#actionViewDetail`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct ActionViewDetail {
     pub action: ActionType,
@@ -65,9 +58,8 @@ pub struct ActionViewDetail {
     pub subject: Box<ActionViewDetailSubjectEnum>,
     pub subject_blobs: Vec<BlobView>,
 }
-
-// com.atproto.admin.defs#blobView
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[doc = "`com.atproto.admin.defs#blobView`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct BlobView {
     pub cid: String,
@@ -79,33 +71,28 @@ pub struct BlobView {
     pub moderation: Option<Moderation>,
     pub size: i32,
 }
-
-// com.atproto.admin.defs#escalate
-/// Moderation action type: Escalate. Indicates that the content has been flagged for additional review.
+#[doc = "`com.atproto.admin.defs#escalate`"]
+#[doc = "Moderation action type: Escalate. Indicates that the content has been flagged for additional review."]
 pub struct Escalate;
-
-// com.atproto.admin.defs#flag
-/// Moderation action type: Flag. Indicates that the content was reviewed and considered to violate PDS rules, but may still be served.
+#[doc = "`com.atproto.admin.defs#flag`"]
+#[doc = "Moderation action type: Flag. Indicates that the content was reviewed and considered to violate PDS rules, but may still be served."]
 pub struct Flag;
-
-// com.atproto.admin.defs#imageDetails
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[doc = "`com.atproto.admin.defs#imageDetails`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct ImageDetails {
     pub height: i32,
     pub width: i32,
 }
-
-// com.atproto.admin.defs#moderation
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[doc = "`com.atproto.admin.defs#moderation`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Moderation {
     #[serde(skip_serializing_if = "Option::is_none")]
     pub current_action: Option<ActionViewCurrent>,
 }
-
-// com.atproto.admin.defs#moderationDetail
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[doc = "`com.atproto.admin.defs#moderationDetail`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct ModerationDetail {
     pub actions: Vec<ActionView>,
@@ -113,9 +100,8 @@ pub struct ModerationDetail {
     pub current_action: Option<ActionViewCurrent>,
     pub reports: Vec<ReportView>,
 }
-
-// com.atproto.admin.defs#recordView
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[doc = "`com.atproto.admin.defs#recordView`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct RecordView {
     pub blob_cids: Vec<String>,
@@ -126,9 +112,8 @@ pub struct RecordView {
     pub uri: String,
     pub value: crate::records::Record,
 }
-
-// com.atproto.admin.defs#recordViewDetail
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[doc = "`com.atproto.admin.defs#recordViewDetail`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct RecordViewDetail {
     pub blobs: Vec<BlobView>,
@@ -141,16 +126,14 @@ pub struct RecordViewDetail {
     pub uri: String,
     pub value: crate::records::Record,
 }
-
-// com.atproto.admin.defs#repoRef
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[doc = "`com.atproto.admin.defs#repoRef`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct RepoRef {
     pub did: String,
 }
-
-// com.atproto.admin.defs#repoView
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[doc = "`com.atproto.admin.defs#repoView`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct RepoView {
     pub did: String,
@@ -161,11 +144,10 @@ pub struct RepoView {
     #[serde(skip_serializing_if = "Option::is_none")]
     pub invited_by: Option<crate::com::atproto::server::defs::InviteCode>,
     pub moderation: Moderation,
-    // pub related_records: Vec<...>
+    pub related_records: Vec<crate::records::Record>,
 }
-
-// com.atproto.admin.defs#repoViewDetail
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[doc = "`com.atproto.admin.defs#repoViewDetail`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct RepoViewDetail {
     pub did: String,
@@ -180,11 +162,10 @@ pub struct RepoViewDetail {
     #[serde(skip_serializing_if = "Option::is_none")]
     pub labels: Option<Vec<crate::com::atproto::label::defs::Label>>,
     pub moderation: ModerationDetail,
-    // pub related_records: Vec<...>
+    pub related_records: Vec<crate::records::Record>,
 }
-
-// com.atproto.admin.defs#reportView
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[doc = "`com.atproto.admin.defs#reportView`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct ReportView {
     pub created_at: String,
@@ -196,9 +177,8 @@ pub struct ReportView {
     pub resolved_by_action_ids: Vec<i32>,
     pub subject: Box<ReportViewSubjectEnum>,
 }
-
-// com.atproto.admin.defs#reportViewDetail
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[doc = "`com.atproto.admin.defs#reportViewDetail`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct ReportViewDetail {
     pub created_at: String,
@@ -210,22 +190,18 @@ pub struct ReportViewDetail {
     pub resolved_by_actions: Vec<crate::com::atproto::admin::defs::ActionView>,
     pub subject: Box<ReportViewDetailSubjectEnum>,
 }
-
-// com.atproto.admin.defs#takedown
-/// Moderation action type: Takedown. Indicates that content should not be served by the PDS.
+#[doc = "`com.atproto.admin.defs#takedown`"]
+#[doc = "Moderation action type: Takedown. Indicates that content should not be served by the PDS."]
 pub struct Takedown;
-
-// com.atproto.admin.defs#videoDetails
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[doc = "`com.atproto.admin.defs#videoDetails`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct VideoDetails {
     pub height: i32,
     pub length: i32,
     pub width: i32,
 }
-
-#[allow(clippy::large_enum_variant)]
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "$type")]
 pub enum ActionViewDetailSubjectEnum {
     #[serde(rename = "com.atproto.admin.defs#repoView")]
@@ -233,9 +209,7 @@ pub enum ActionViewDetailSubjectEnum {
     #[serde(rename = "com.atproto.admin.defs#recordView")]
     RecordView(RecordView),
 }
-
-#[allow(clippy::large_enum_variant)]
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "$type")]
 pub enum ActionViewSubjectEnum {
     #[serde(rename = "com.atproto.admin.defs#repoRef")]
@@ -243,9 +217,7 @@ pub enum ActionViewSubjectEnum {
     #[serde(rename = "com.atproto.repo.strongRef")]
     ComAtprotoRepoStrongRefMain(crate::com::atproto::repo::strong_ref::Main),
 }
-
-#[allow(clippy::large_enum_variant)]
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "$type")]
 pub enum BlobViewDetailsEnum {
     #[serde(rename = "com.atproto.admin.defs#imageDetails")]
@@ -253,9 +225,7 @@ pub enum BlobViewDetailsEnum {
     #[serde(rename = "com.atproto.admin.defs#videoDetails")]
     VideoDetails(VideoDetails),
 }
-
-#[allow(clippy::large_enum_variant)]
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "$type")]
 pub enum ReportViewDetailSubjectEnum {
     #[serde(rename = "com.atproto.admin.defs#repoView")]
@@ -263,9 +233,7 @@ pub enum ReportViewDetailSubjectEnum {
     #[serde(rename = "com.atproto.admin.defs#recordView")]
     RecordView(RecordView),
 }
-
-#[allow(clippy::large_enum_variant)]
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "$type")]
 pub enum ReportViewSubjectEnum {
     #[serde(rename = "com.atproto.admin.defs#repoRef")]
diff --git a/atrium-api/src/com/atproto/admin/disable_invite_codes.rs b/atrium-api/src/com/atproto/admin/disable_invite_codes.rs
index 97d70e54..eee14f43 100644
--- a/atrium-api/src/com/atproto/admin/disable_invite_codes.rs
+++ b/atrium-api/src/com/atproto/admin/disable_invite_codes.rs
@@ -1,7 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `com.atproto.admin.disableInviteCodes` namespace.
-
-/// Disable some set of codes and/or all codes associated with a set of users
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `com.atproto.admin.disableInviteCodes` namespace."]
+#[doc = "`com.atproto.admin.disableInviteCodes`"]
+#[doc = "Disable some set of codes and/or all codes associated with a set of users"]
 #[async_trait::async_trait]
 pub trait DisableInviteCodes: crate::xrpc::XrpcClient {
     async fn disable_invite_codes(&self, input: Input) -> Result<(), Box<dyn std::error::Error>> {
@@ -17,8 +17,7 @@ pub trait DisableInviteCodes: crate::xrpc::XrpcClient {
         Ok(())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Input {
     #[serde(skip_serializing_if = "Option::is_none")]
@@ -26,7 +25,6 @@ pub struct Input {
     #[serde(skip_serializing_if = "Option::is_none")]
     pub codes: Option<Vec<String>>,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {}
diff --git a/atrium-api/src/com/atproto/admin/get_invite_codes.rs b/atrium-api/src/com/atproto/admin/get_invite_codes.rs
index 488bfff4..e79fbcbf 100644
--- a/atrium-api/src/com/atproto/admin/get_invite_codes.rs
+++ b/atrium-api/src/com/atproto/admin/get_invite_codes.rs
@@ -1,7 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `com.atproto.admin.getInviteCodes` namespace.
-
-/// Admin view of invite codes
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `com.atproto.admin.getInviteCodes` namespace."]
+#[doc = "`com.atproto.admin.getInviteCodes`"]
+#[doc = "Admin view of invite codes"]
 #[async_trait::async_trait]
 pub trait GetInviteCodes: crate::xrpc::XrpcClient {
     async fn get_invite_codes(
@@ -20,8 +20,7 @@ pub trait GetInviteCodes: crate::xrpc::XrpcClient {
         serde_json::from_slice(&body).map_err(|e| e.into())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Parameters {
     #[serde(skip_serializing_if = "Option::is_none")]
@@ -31,15 +30,13 @@ pub struct Parameters {
     #[serde(skip_serializing_if = "Option::is_none")]
     pub sort: Option<String>,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Output {
     pub codes: Vec<crate::com::atproto::server::defs::InviteCode>,
     #[serde(skip_serializing_if = "Option::is_none")]
     pub cursor: Option<String>,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {}
diff --git a/atrium-api/src/com/atproto/admin/get_moderation_action.rs b/atrium-api/src/com/atproto/admin/get_moderation_action.rs
index 8cb98ef9..59c7e29e 100644
--- a/atrium-api/src/com/atproto/admin/get_moderation_action.rs
+++ b/atrium-api/src/com/atproto/admin/get_moderation_action.rs
@@ -1,7 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `com.atproto.admin.getModerationAction` namespace.
-
-/// View details about a moderation action.
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `com.atproto.admin.getModerationAction` namespace."]
+#[doc = "`com.atproto.admin.getModerationAction`"]
+#[doc = "View details about a moderation action."]
 #[async_trait::async_trait]
 pub trait GetModerationAction: crate::xrpc::XrpcClient {
     async fn get_moderation_action(
@@ -20,15 +20,12 @@ pub trait GetModerationAction: crate::xrpc::XrpcClient {
         serde_json::from_slice(&body).map_err(|e| e.into())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Parameters {
     pub id: i32,
 }
-
 pub type Output = crate::com::atproto::admin::defs::ActionViewDetail;
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {}
diff --git a/atrium-api/src/com/atproto/admin/get_moderation_actions.rs b/atrium-api/src/com/atproto/admin/get_moderation_actions.rs
index 1756f563..dd925c73 100644
--- a/atrium-api/src/com/atproto/admin/get_moderation_actions.rs
+++ b/atrium-api/src/com/atproto/admin/get_moderation_actions.rs
@@ -1,7 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `com.atproto.admin.getModerationActions` namespace.
-
-/// List moderation actions related to a subject.
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `com.atproto.admin.getModerationActions` namespace."]
+#[doc = "`com.atproto.admin.getModerationActions`"]
+#[doc = "List moderation actions related to a subject."]
 #[async_trait::async_trait]
 pub trait GetModerationActions: crate::xrpc::XrpcClient {
     async fn get_moderation_actions(
@@ -20,8 +20,7 @@ pub trait GetModerationActions: crate::xrpc::XrpcClient {
         serde_json::from_slice(&body).map_err(|e| e.into())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Parameters {
     #[serde(skip_serializing_if = "Option::is_none")]
@@ -31,15 +30,13 @@ pub struct Parameters {
     #[serde(skip_serializing_if = "Option::is_none")]
     pub subject: Option<String>,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Output {
     pub actions: Vec<crate::com::atproto::admin::defs::ActionView>,
     #[serde(skip_serializing_if = "Option::is_none")]
     pub cursor: Option<String>,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {}
diff --git a/atrium-api/src/com/atproto/admin/get_moderation_report.rs b/atrium-api/src/com/atproto/admin/get_moderation_report.rs
index b59113b4..8d885bd9 100644
--- a/atrium-api/src/com/atproto/admin/get_moderation_report.rs
+++ b/atrium-api/src/com/atproto/admin/get_moderation_report.rs
@@ -1,7 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `com.atproto.admin.getModerationReport` namespace.
-
-/// View details about a moderation report.
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `com.atproto.admin.getModerationReport` namespace."]
+#[doc = "`com.atproto.admin.getModerationReport`"]
+#[doc = "View details about a moderation report."]
 #[async_trait::async_trait]
 pub trait GetModerationReport: crate::xrpc::XrpcClient {
     async fn get_moderation_report(
@@ -20,15 +20,12 @@ pub trait GetModerationReport: crate::xrpc::XrpcClient {
         serde_json::from_slice(&body).map_err(|e| e.into())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Parameters {
     pub id: i32,
 }
-
 pub type Output = crate::com::atproto::admin::defs::ReportViewDetail;
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {}
diff --git a/atrium-api/src/com/atproto/admin/get_moderation_reports.rs b/atrium-api/src/com/atproto/admin/get_moderation_reports.rs
index b0d83d39..17adae13 100644
--- a/atrium-api/src/com/atproto/admin/get_moderation_reports.rs
+++ b/atrium-api/src/com/atproto/admin/get_moderation_reports.rs
@@ -1,7 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `com.atproto.admin.getModerationReports` namespace.
-
-/// List moderation reports related to a subject.
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `com.atproto.admin.getModerationReports` namespace."]
+#[doc = "`com.atproto.admin.getModerationReports`"]
+#[doc = "List moderation reports related to a subject."]
 #[async_trait::async_trait]
 pub trait GetModerationReports: crate::xrpc::XrpcClient {
     async fn get_moderation_reports(
@@ -20,8 +20,7 @@ pub trait GetModerationReports: crate::xrpc::XrpcClient {
         serde_json::from_slice(&body).map_err(|e| e.into())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Parameters {
     #[serde(skip_serializing_if = "Option::is_none")]
@@ -33,15 +32,13 @@ pub struct Parameters {
     #[serde(skip_serializing_if = "Option::is_none")]
     pub subject: Option<String>,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Output {
     #[serde(skip_serializing_if = "Option::is_none")]
     pub cursor: Option<String>,
     pub reports: Vec<crate::com::atproto::admin::defs::ReportView>,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {}
diff --git a/atrium-api/src/com/atproto/admin/get_record.rs b/atrium-api/src/com/atproto/admin/get_record.rs
index 167b9c79..7b762075 100644
--- a/atrium-api/src/com/atproto/admin/get_record.rs
+++ b/atrium-api/src/com/atproto/admin/get_record.rs
@@ -1,7 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `com.atproto.admin.getRecord` namespace.
-
-/// View details about a record.
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `com.atproto.admin.getRecord` namespace."]
+#[doc = "`com.atproto.admin.getRecord`"]
+#[doc = "View details about a record."]
 #[async_trait::async_trait]
 pub trait GetRecord: crate::xrpc::XrpcClient {
     async fn get_record(&self, params: Parameters) -> Result<Output, Box<dyn std::error::Error>> {
@@ -17,17 +17,14 @@ pub trait GetRecord: crate::xrpc::XrpcClient {
         serde_json::from_slice(&body).map_err(|e| e.into())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Parameters {
     #[serde(skip_serializing_if = "Option::is_none")]
     pub cid: Option<String>,
     pub uri: String,
 }
-
 pub type Output = crate::com::atproto::admin::defs::RecordViewDetail;
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {}
diff --git a/atrium-api/src/com/atproto/admin/get_repo.rs b/atrium-api/src/com/atproto/admin/get_repo.rs
index 62a777d6..579d9c6e 100644
--- a/atrium-api/src/com/atproto/admin/get_repo.rs
+++ b/atrium-api/src/com/atproto/admin/get_repo.rs
@@ -1,7 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `com.atproto.admin.getRepo` namespace.
-
-/// View details about a repository.
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `com.atproto.admin.getRepo` namespace."]
+#[doc = "`com.atproto.admin.getRepo`"]
+#[doc = "View details about a repository."]
 #[async_trait::async_trait]
 pub trait GetRepo: crate::xrpc::XrpcClient {
     async fn get_repo(&self, params: Parameters) -> Result<Output, Box<dyn std::error::Error>> {
@@ -17,15 +17,12 @@ pub trait GetRepo: crate::xrpc::XrpcClient {
         serde_json::from_slice(&body).map_err(|e| e.into())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Parameters {
     pub did: String,
 }
-
 pub type Output = crate::com::atproto::admin::defs::RepoViewDetail;
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {}
diff --git a/atrium-api/src/com/atproto/admin/resolve_moderation_reports.rs b/atrium-api/src/com/atproto/admin/resolve_moderation_reports.rs
index c83843a4..3d081511 100644
--- a/atrium-api/src/com/atproto/admin/resolve_moderation_reports.rs
+++ b/atrium-api/src/com/atproto/admin/resolve_moderation_reports.rs
@@ -1,7 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `com.atproto.admin.resolveModerationReports` namespace.
-
-/// Resolve moderation reports by an action.
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `com.atproto.admin.resolveModerationReports` namespace."]
+#[doc = "`com.atproto.admin.resolveModerationReports`"]
+#[doc = "Resolve moderation reports by an action."]
 #[async_trait::async_trait]
 pub trait ResolveModerationReports: crate::xrpc::XrpcClient {
     async fn resolve_moderation_reports(
@@ -20,17 +20,14 @@ pub trait ResolveModerationReports: crate::xrpc::XrpcClient {
         serde_json::from_slice(&body).map_err(|e| e.into())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Input {
     pub action_id: i32,
     pub created_by: String,
     pub report_ids: Vec<i32>,
 }
-
 pub type Output = crate::com::atproto::admin::defs::ActionView;
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {}
diff --git a/atrium-api/src/com/atproto/admin/reverse_moderation_action.rs b/atrium-api/src/com/atproto/admin/reverse_moderation_action.rs
index a9b201b0..3a8465be 100644
--- a/atrium-api/src/com/atproto/admin/reverse_moderation_action.rs
+++ b/atrium-api/src/com/atproto/admin/reverse_moderation_action.rs
@@ -1,7 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `com.atproto.admin.reverseModerationAction` namespace.
-
-/// Reverse a moderation action.
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `com.atproto.admin.reverseModerationAction` namespace."]
+#[doc = "`com.atproto.admin.reverseModerationAction`"]
+#[doc = "Reverse a moderation action."]
 #[async_trait::async_trait]
 pub trait ReverseModerationAction: crate::xrpc::XrpcClient {
     async fn reverse_moderation_action(
@@ -20,17 +20,14 @@ pub trait ReverseModerationAction: crate::xrpc::XrpcClient {
         serde_json::from_slice(&body).map_err(|e| e.into())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Input {
     pub created_by: String,
     pub id: i32,
     pub reason: String,
 }
-
 pub type Output = crate::com::atproto::admin::defs::ActionView;
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {}
diff --git a/atrium-api/src/com/atproto/admin/search_repos.rs b/atrium-api/src/com/atproto/admin/search_repos.rs
index 74ca2b59..17a74e22 100644
--- a/atrium-api/src/com/atproto/admin/search_repos.rs
+++ b/atrium-api/src/com/atproto/admin/search_repos.rs
@@ -1,7 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `com.atproto.admin.searchRepos` namespace.
-
-/// Find repositories based on a search term.
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `com.atproto.admin.searchRepos` namespace."]
+#[doc = "`com.atproto.admin.searchRepos`"]
+#[doc = "Find repositories based on a search term."]
 #[async_trait::async_trait]
 pub trait SearchRepos: crate::xrpc::XrpcClient {
     async fn search_repos(&self, params: Parameters) -> Result<Output, Box<dyn std::error::Error>> {
@@ -17,8 +17,7 @@ pub trait SearchRepos: crate::xrpc::XrpcClient {
         serde_json::from_slice(&body).map_err(|e| e.into())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Parameters {
     #[serde(skip_serializing_if = "Option::is_none")]
@@ -30,15 +29,13 @@ pub struct Parameters {
     #[serde(skip_serializing_if = "Option::is_none")]
     pub term: Option<String>,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Output {
     #[serde(skip_serializing_if = "Option::is_none")]
     pub cursor: Option<String>,
     pub repos: Vec<crate::com::atproto::admin::defs::RepoView>,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {}
diff --git a/atrium-api/src/com/atproto/admin/take_moderation_action.rs b/atrium-api/src/com/atproto/admin/take_moderation_action.rs
index 7202de0f..6d0fec52 100644
--- a/atrium-api/src/com/atproto/admin/take_moderation_action.rs
+++ b/atrium-api/src/com/atproto/admin/take_moderation_action.rs
@@ -1,7 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `com.atproto.admin.takeModerationAction` namespace.
-
-/// Take a moderation action on a repo.
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `com.atproto.admin.takeModerationAction` namespace."]
+#[doc = "`com.atproto.admin.takeModerationAction`"]
+#[doc = "Take a moderation action on a repo."]
 #[async_trait::async_trait]
 pub trait TakeModerationAction: crate::xrpc::XrpcClient {
     async fn take_moderation_action(
@@ -20,8 +20,7 @@ pub trait TakeModerationAction: crate::xrpc::XrpcClient {
         serde_json::from_slice(&body).map_err(|e| e.into())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Input {
     pub action: String,
@@ -35,17 +34,13 @@ pub struct Input {
     #[serde(skip_serializing_if = "Option::is_none")]
     pub subject_blob_cids: Option<Vec<String>>,
 }
-
 pub type Output = crate::com::atproto::admin::defs::ActionView;
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {
     SubjectHasAction(Option<String>),
 }
-
-#[allow(clippy::large_enum_variant)]
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "$type")]
 pub enum InputSubjectEnum {
     #[serde(rename = "com.atproto.admin.defs#repoRef")]
diff --git a/atrium-api/src/com/atproto/admin/update_account_email.rs b/atrium-api/src/com/atproto/admin/update_account_email.rs
index 5253d683..d57596f2 100644
--- a/atrium-api/src/com/atproto/admin/update_account_email.rs
+++ b/atrium-api/src/com/atproto/admin/update_account_email.rs
@@ -1,7 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `com.atproto.admin.updateAccountEmail` namespace.
-
-/// Administrative action to update an account's email
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `com.atproto.admin.updateAccountEmail` namespace."]
+#[doc = "`com.atproto.admin.updateAccountEmail`"]
+#[doc = "Administrative action to update an account's email"]
 #[async_trait::async_trait]
 pub trait UpdateAccountEmail: crate::xrpc::XrpcClient {
     async fn update_account_email(&self, input: Input) -> Result<(), Box<dyn std::error::Error>> {
@@ -17,15 +17,13 @@ pub trait UpdateAccountEmail: crate::xrpc::XrpcClient {
         Ok(())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Input {
-    /// The handle or DID of the repo.
+    #[doc = "The handle or DID of the repo."]
     pub account: String,
     pub email: String,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {}
diff --git a/atrium-api/src/com/atproto/admin/update_account_handle.rs b/atrium-api/src/com/atproto/admin/update_account_handle.rs
index fcf83d8a..238db3b6 100644
--- a/atrium-api/src/com/atproto/admin/update_account_handle.rs
+++ b/atrium-api/src/com/atproto/admin/update_account_handle.rs
@@ -1,7 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `com.atproto.admin.updateAccountHandle` namespace.
-
-/// Administrative action to update an account's handle
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `com.atproto.admin.updateAccountHandle` namespace."]
+#[doc = "`com.atproto.admin.updateAccountHandle`"]
+#[doc = "Administrative action to update an account's handle"]
 #[async_trait::async_trait]
 pub trait UpdateAccountHandle: crate::xrpc::XrpcClient {
     async fn update_account_handle(&self, input: Input) -> Result<(), Box<dyn std::error::Error>> {
@@ -17,14 +17,12 @@ pub trait UpdateAccountHandle: crate::xrpc::XrpcClient {
         Ok(())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Input {
     pub did: String,
     pub handle: String,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {}
diff --git a/atrium-api/src/com/atproto/identity.rs b/atrium-api/src/com/atproto/identity.rs
index 19c1cd2d..4515811a 100644
--- a/atrium-api/src/com/atproto/identity.rs
+++ b/atrium-api/src/com/atproto/identity.rs
@@ -1,3 +1,3 @@
-// This file is generated by atrium-codegen. Do not edit.
+// This file is generated by atrium-codegen. DO NOT EDIT.
 pub mod resolve_handle;
 pub mod update_handle;
diff --git a/atrium-api/src/com/atproto/identity/resolve_handle.rs b/atrium-api/src/com/atproto/identity/resolve_handle.rs
index be412209..7d7ad0a4 100644
--- a/atrium-api/src/com/atproto/identity/resolve_handle.rs
+++ b/atrium-api/src/com/atproto/identity/resolve_handle.rs
@@ -1,7 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `com.atproto.identity.resolveHandle` namespace.
-
-/// Provides the DID of a repo.
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `com.atproto.identity.resolveHandle` namespace."]
+#[doc = "`com.atproto.identity.resolveHandle`"]
+#[doc = "Provides the DID of a repo."]
 #[async_trait::async_trait]
 pub trait ResolveHandle: crate::xrpc::XrpcClient {
     async fn resolve_handle(
@@ -20,21 +20,18 @@ pub trait ResolveHandle: crate::xrpc::XrpcClient {
         serde_json::from_slice(&body).map_err(|e| e.into())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Parameters {
-    /// The handle to resolve. If not supplied, will resolve the host's own handle.
+    #[doc = "The handle to resolve. If not supplied, will resolve the host's own handle."]
     #[serde(skip_serializing_if = "Option::is_none")]
     pub handle: Option<String>,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Output {
     pub did: String,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {}
diff --git a/atrium-api/src/com/atproto/identity/update_handle.rs b/atrium-api/src/com/atproto/identity/update_handle.rs
index 3bb7ff03..46b32335 100644
--- a/atrium-api/src/com/atproto/identity/update_handle.rs
+++ b/atrium-api/src/com/atproto/identity/update_handle.rs
@@ -1,7 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `com.atproto.identity.updateHandle` namespace.
-
-/// Updates the handle of the account
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `com.atproto.identity.updateHandle` namespace."]
+#[doc = "`com.atproto.identity.updateHandle`"]
+#[doc = "Updates the handle of the account"]
 #[async_trait::async_trait]
 pub trait UpdateHandle: crate::xrpc::XrpcClient {
     async fn update_handle(&self, input: Input) -> Result<(), Box<dyn std::error::Error>> {
@@ -17,13 +17,11 @@ pub trait UpdateHandle: crate::xrpc::XrpcClient {
         Ok(())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Input {
     pub handle: String,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {}
diff --git a/atrium-api/src/com/atproto/label.rs b/atrium-api/src/com/atproto/label.rs
index 09d9973f..8130cb22 100644
--- a/atrium-api/src/com/atproto/label.rs
+++ b/atrium-api/src/com/atproto/label.rs
@@ -1,4 +1,4 @@
-// This file is generated by atrium-codegen. Do not edit.
+// This file is generated by atrium-codegen. DO NOT EDIT.
 pub mod defs;
 pub mod query_labels;
 pub mod subscribe_labels;
diff --git a/atrium-api/src/com/atproto/label/defs.rs b/atrium-api/src/com/atproto/label/defs.rs
index a641b944..263c89a1 100644
--- a/atrium-api/src/com/atproto/label/defs.rs
+++ b/atrium-api/src/com/atproto/label/defs.rs
@@ -1,23 +1,22 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `com.atproto.label.defs` namespace.
-
-// com.atproto.label.defs#label
-/// Metadata tag on an atproto resource (eg, repo or record)
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `com.atproto.label.defs` namespace."]
+#[doc = "`com.atproto.label.defs#label`"]
+#[doc = "Metadata tag on an atproto resource (eg, repo or record)"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Label {
-    /// optionally, CID specifying the specific version of 'uri' resource this label applies to
+    #[doc = "optionally, CID specifying the specific version of 'uri' resource this label applies to"]
     #[serde(skip_serializing_if = "Option::is_none")]
     pub cid: Option<String>,
-    /// timestamp when this label was created
+    #[doc = "timestamp when this label was created"]
     pub cts: String,
-    /// if true, this is a negation label, overwriting a previous label
+    #[doc = "if true, this is a negation label, overwriting a previous label"]
     #[serde(skip_serializing_if = "Option::is_none")]
     pub neg: Option<bool>,
-    /// DID of the actor who created this label
+    #[doc = "DID of the actor who created this label"]
     pub src: String,
-    /// AT URI of the record, repository (account), or other resource which this label applies to
+    #[doc = "AT URI of the record, repository (account), or other resource which this label applies to"]
     pub uri: String,
-    /// the short string name of the value or type of this label
+    #[doc = "the short string name of the value or type of this label"]
     pub val: String,
 }
diff --git a/atrium-api/src/com/atproto/label/query_labels.rs b/atrium-api/src/com/atproto/label/query_labels.rs
index 97084d5d..e7ecc12d 100644
--- a/atrium-api/src/com/atproto/label/query_labels.rs
+++ b/atrium-api/src/com/atproto/label/query_labels.rs
@@ -1,7 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `com.atproto.label.queryLabels` namespace.
-
-/// Find labels relevant to the provided URI patterns.
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `com.atproto.label.queryLabels` namespace."]
+#[doc = "`com.atproto.label.queryLabels`"]
+#[doc = "Find labels relevant to the provided URI patterns."]
 #[async_trait::async_trait]
 pub trait QueryLabels: crate::xrpc::XrpcClient {
     async fn query_labels(&self, params: Parameters) -> Result<Output, Box<dyn std::error::Error>> {
@@ -17,29 +17,26 @@ pub trait QueryLabels: crate::xrpc::XrpcClient {
         serde_json::from_slice(&body).map_err(|e| e.into())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Parameters {
     #[serde(skip_serializing_if = "Option::is_none")]
     pub cursor: Option<String>,
     #[serde(skip_serializing_if = "Option::is_none")]
     pub limit: Option<i32>,
-    /// Optional list of label sources (DIDs) to filter on
+    #[doc = "Optional list of label sources (DIDs) to filter on"]
     #[serde(skip_serializing_if = "Option::is_none")]
     pub sources: Option<Vec<String>>,
-    /// List of AT URI patterns to match (boolean 'OR'). Each may be a prefix (ending with '*'; will match inclusive of the string leading to '*'), or a full URI
+    #[doc = "List of AT URI patterns to match (boolean 'OR'). Each may be a prefix (ending with '*'; will match inclusive of the string leading to '*'), or a full URI"]
     pub uri_patterns: Vec<String>,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Output {
     #[serde(skip_serializing_if = "Option::is_none")]
     pub cursor: Option<String>,
     pub labels: Vec<crate::com::atproto::label::defs::Label>,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {}
diff --git a/atrium-api/src/com/atproto/label/subscribe_labels.rs b/atrium-api/src/com/atproto/label/subscribe_labels.rs
index 1b5a41ec..8f79fc95 100644
--- a/atrium-api/src/com/atproto/label/subscribe_labels.rs
+++ b/atrium-api/src/com/atproto/label/subscribe_labels.rs
@@ -1,20 +1,18 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `com.atproto.label.subscribeLabels` namespace.
-
-// com.atproto.label.subscribeLabels
-// TODO
-
-// com.atproto.label.subscribeLabels#info
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `com.atproto.label.subscribeLabels` namespace."]
+#[doc = "`com.atproto.label.subscribeLabels`"]
+#[doc = "Subscribe to label updates"]
+pub struct SubscribeLabels;
+#[doc = "`com.atproto.label.subscribeLabels#info`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Info {
     #[serde(skip_serializing_if = "Option::is_none")]
     pub message: Option<String>,
     pub name: String,
 }
-
-// com.atproto.label.subscribeLabels#labels
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[doc = "`com.atproto.label.subscribeLabels#labels`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Labels {
     pub labels: Vec<crate::com::atproto::label::defs::Label>,
diff --git a/atrium-api/src/com/atproto/moderation.rs b/atrium-api/src/com/atproto/moderation.rs
index c253ed83..1d40f805 100644
--- a/atrium-api/src/com/atproto/moderation.rs
+++ b/atrium-api/src/com/atproto/moderation.rs
@@ -1,3 +1,3 @@
-// This file is generated by atrium-codegen. Do not edit.
+// This file is generated by atrium-codegen. DO NOT EDIT.
 pub mod create_report;
 pub mod defs;
diff --git a/atrium-api/src/com/atproto/moderation/create_report.rs b/atrium-api/src/com/atproto/moderation/create_report.rs
index 3bf0d03c..fd604885 100644
--- a/atrium-api/src/com/atproto/moderation/create_report.rs
+++ b/atrium-api/src/com/atproto/moderation/create_report.rs
@@ -1,7 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `com.atproto.moderation.createReport` namespace.
-
-/// Report a repo or a record.
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `com.atproto.moderation.createReport` namespace."]
+#[doc = "`com.atproto.moderation.createReport`"]
+#[doc = "Report a repo or a record."]
 #[async_trait::async_trait]
 pub trait CreateReport: crate::xrpc::XrpcClient {
     async fn create_report(&self, input: Input) -> Result<Output, Box<dyn std::error::Error>> {
@@ -17,8 +17,7 @@ pub trait CreateReport: crate::xrpc::XrpcClient {
         serde_json::from_slice(&body).map_err(|e| e.into())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Input {
     #[serde(skip_serializing_if = "Option::is_none")]
@@ -26,8 +25,7 @@ pub struct Input {
     pub reason_type: crate::com::atproto::moderation::defs::ReasonType,
     pub subject: Box<InputSubjectEnum>,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Output {
     pub created_at: String,
@@ -38,13 +36,10 @@ pub struct Output {
     pub reported_by: String,
     pub subject: Box<OutputSubjectEnum>,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {}
-
-#[allow(clippy::large_enum_variant)]
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "$type")]
 pub enum InputSubjectEnum {
     #[serde(rename = "com.atproto.admin.defs#repoRef")]
@@ -52,9 +47,7 @@ pub enum InputSubjectEnum {
     #[serde(rename = "com.atproto.repo.strongRef")]
     ComAtprotoRepoStrongRefMain(crate::com::atproto::repo::strong_ref::Main),
 }
-
-#[allow(clippy::large_enum_variant)]
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "$type")]
 pub enum OutputSubjectEnum {
     #[serde(rename = "com.atproto.admin.defs#repoRef")]
diff --git a/atrium-api/src/com/atproto/moderation/defs.rs b/atrium-api/src/com/atproto/moderation/defs.rs
index 8d98d5c9..05af246f 100644
--- a/atrium-api/src/com/atproto/moderation/defs.rs
+++ b/atrium-api/src/com/atproto/moderation/defs.rs
@@ -1,30 +1,22 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `com.atproto.moderation.defs` namespace.
-
-// com.atproto.moderation.defs#reasonMisleading
-/// Misleading identity, affiliation, or content
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `com.atproto.moderation.defs` namespace."]
+#[doc = "`com.atproto.moderation.defs#reasonMisleading`"]
+#[doc = "Misleading identity, affiliation, or content"]
 pub struct ReasonMisleading;
-
-// com.atproto.moderation.defs#reasonOther
-/// Other: reports not falling under another report category
+#[doc = "`com.atproto.moderation.defs#reasonOther`"]
+#[doc = "Other: reports not falling under another report category"]
 pub struct ReasonOther;
-
-// com.atproto.moderation.defs#reasonRude
-/// Rude, harassing, explicit, or otherwise unwelcoming behavior
+#[doc = "`com.atproto.moderation.defs#reasonRude`"]
+#[doc = "Rude, harassing, explicit, or otherwise unwelcoming behavior"]
 pub struct ReasonRude;
-
-// com.atproto.moderation.defs#reasonSexual
-/// Unwanted or mis-labeled sexual content
+#[doc = "`com.atproto.moderation.defs#reasonSexual`"]
+#[doc = "Unwanted or mis-labeled sexual content"]
 pub struct ReasonSexual;
-
-// com.atproto.moderation.defs#reasonSpam
-/// Spam: frequent unwanted promotion, replies, mentions
+#[doc = "`com.atproto.moderation.defs#reasonSpam`"]
+#[doc = "Spam: frequent unwanted promotion, replies, mentions"]
 pub struct ReasonSpam;
-
-// com.atproto.moderation.defs#reasonType
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
-pub struct ReasonType;
-
-// com.atproto.moderation.defs#reasonViolation
-/// Direct violation of server rules, laws, terms of service
+#[doc = "`com.atproto.moderation.defs#reasonType`"]
+pub type ReasonType = String;
+#[doc = "`com.atproto.moderation.defs#reasonViolation`"]
+#[doc = "Direct violation of server rules, laws, terms of service"]
 pub struct ReasonViolation;
diff --git a/atrium-api/src/com/atproto/repo.rs b/atrium-api/src/com/atproto/repo.rs
index 58f33c97..c0daaa66 100644
--- a/atrium-api/src/com/atproto/repo.rs
+++ b/atrium-api/src/com/atproto/repo.rs
@@ -1,4 +1,4 @@
-// This file is generated by atrium-codegen. Do not edit.
+// This file is generated by atrium-codegen. DO NOT EDIT.
 pub mod apply_writes;
 pub mod create_record;
 pub mod delete_record;
diff --git a/atrium-api/src/com/atproto/repo/apply_writes.rs b/atrium-api/src/com/atproto/repo/apply_writes.rs
index 2622d48c..10bf45c2 100644
--- a/atrium-api/src/com/atproto/repo/apply_writes.rs
+++ b/atrium-api/src/com/atproto/repo/apply_writes.rs
@@ -1,7 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `com.atproto.repo.applyWrites` namespace.
-
-/// Apply a batch transaction of creates, updates, and deletes.
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `com.atproto.repo.applyWrites` namespace."]
+#[doc = "`com.atproto.repo.applyWrites`"]
+#[doc = "Apply a batch transaction of creates, updates, and deletes."]
 #[async_trait::async_trait]
 pub trait ApplyWrites: crate::xrpc::XrpcClient {
     async fn apply_writes(&self, input: Input) -> Result<(), Box<dyn std::error::Error>> {
@@ -17,29 +17,26 @@ pub trait ApplyWrites: crate::xrpc::XrpcClient {
         Ok(())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Input {
-    /// The handle or DID of the repo.
+    #[doc = "The handle or DID of the repo."]
     pub repo: String,
     #[serde(skip_serializing_if = "Option::is_none")]
     pub swap_commit: Option<String>,
-    /// Validate the records?
+    #[doc = "Validate the records?"]
     #[serde(skip_serializing_if = "Option::is_none")]
     pub validate: Option<bool>,
-    pub writes: Vec<InputWritesItem>,
+    pub writes: Vec<Box<InputWritesItem>>,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {
     InvalidSwap(Option<String>),
 }
-
-// com.atproto.repo.applyWrites#create
-/// Create a new record.
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[doc = "`com.atproto.repo.applyWrites#create`"]
+#[doc = "Create a new record."]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Create {
     pub collection: String,
@@ -47,28 +44,24 @@ pub struct Create {
     pub rkey: Option<String>,
     pub value: crate::records::Record,
 }
-
-// com.atproto.repo.applyWrites#delete
-/// Delete an existing record.
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[doc = "`com.atproto.repo.applyWrites#delete`"]
+#[doc = "Delete an existing record."]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Delete {
     pub collection: String,
     pub rkey: String,
 }
-
-// com.atproto.repo.applyWrites#update
-/// Update an existing record.
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[doc = "`com.atproto.repo.applyWrites#update`"]
+#[doc = "Update an existing record."]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Update {
     pub collection: String,
     pub rkey: String,
     pub value: crate::records::Record,
 }
-
-#[allow(clippy::large_enum_variant)]
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "$type")]
 pub enum InputWritesItem {
     #[serde(rename = "com.atproto.repo.applyWrites#create")]
diff --git a/atrium-api/src/com/atproto/repo/create_record.rs b/atrium-api/src/com/atproto/repo/create_record.rs
index 85d66715..679bf120 100644
--- a/atrium-api/src/com/atproto/repo/create_record.rs
+++ b/atrium-api/src/com/atproto/repo/create_record.rs
@@ -1,7 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `com.atproto.repo.createRecord` namespace.
-
-/// Create a new record.
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `com.atproto.repo.createRecord` namespace."]
+#[doc = "`com.atproto.repo.createRecord`"]
+#[doc = "Create a new record."]
 #[async_trait::async_trait]
 pub trait CreateRecord: crate::xrpc::XrpcClient {
     async fn create_record(&self, input: Input) -> Result<Output, Box<dyn std::error::Error>> {
@@ -17,35 +17,32 @@ pub trait CreateRecord: crate::xrpc::XrpcClient {
         serde_json::from_slice(&body).map_err(|e| e.into())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Input {
-    /// The NSID of the record collection.
+    #[doc = "The NSID of the record collection."]
     pub collection: String,
-    /// The record to create.
+    #[doc = "The record to create."]
     pub record: crate::records::Record,
-    /// The handle or DID of the repo.
+    #[doc = "The handle or DID of the repo."]
     pub repo: String,
-    /// The key of the record.
+    #[doc = "The key of the record."]
     #[serde(skip_serializing_if = "Option::is_none")]
     pub rkey: Option<String>,
-    /// Compare and swap with the previous commit by cid.
+    #[doc = "Compare and swap with the previous commit by cid."]
     #[serde(skip_serializing_if = "Option::is_none")]
     pub swap_commit: Option<String>,
-    /// Validate the record?
+    #[doc = "Validate the record?"]
     #[serde(skip_serializing_if = "Option::is_none")]
     pub validate: Option<bool>,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Output {
     pub cid: String,
     pub uri: String,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {
     InvalidSwap(Option<String>),
diff --git a/atrium-api/src/com/atproto/repo/delete_record.rs b/atrium-api/src/com/atproto/repo/delete_record.rs
index b46f22aa..9932fa84 100644
--- a/atrium-api/src/com/atproto/repo/delete_record.rs
+++ b/atrium-api/src/com/atproto/repo/delete_record.rs
@@ -1,7 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `com.atproto.repo.deleteRecord` namespace.
-
-/// Delete a record, or ensure it doesn't exist.
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `com.atproto.repo.deleteRecord` namespace."]
+#[doc = "`com.atproto.repo.deleteRecord`"]
+#[doc = "Delete a record, or ensure it doesn't exist."]
 #[async_trait::async_trait]
 pub trait DeleteRecord: crate::xrpc::XrpcClient {
     async fn delete_record(&self, input: Input) -> Result<(), Box<dyn std::error::Error>> {
@@ -17,25 +17,23 @@ pub trait DeleteRecord: crate::xrpc::XrpcClient {
         Ok(())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Input {
-    /// The NSID of the record collection.
+    #[doc = "The NSID of the record collection."]
     pub collection: String,
-    /// The handle or DID of the repo.
+    #[doc = "The handle or DID of the repo."]
     pub repo: String,
-    /// The key of the record.
+    #[doc = "The key of the record."]
     pub rkey: String,
-    /// Compare and swap with the previous commit by cid.
+    #[doc = "Compare and swap with the previous commit by cid."]
     #[serde(skip_serializing_if = "Option::is_none")]
     pub swap_commit: Option<String>,
-    /// Compare and swap with the previous record by cid.
+    #[doc = "Compare and swap with the previous record by cid."]
     #[serde(skip_serializing_if = "Option::is_none")]
     pub swap_record: Option<String>,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {
     InvalidSwap(Option<String>),
diff --git a/atrium-api/src/com/atproto/repo/describe_repo.rs b/atrium-api/src/com/atproto/repo/describe_repo.rs
index b5fb5ffc..86a915d6 100644
--- a/atrium-api/src/com/atproto/repo/describe_repo.rs
+++ b/atrium-api/src/com/atproto/repo/describe_repo.rs
@@ -1,7 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `com.atproto.repo.describeRepo` namespace.
-
-/// Get information about the repo, including the list of collections.
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `com.atproto.repo.describeRepo` namespace."]
+#[doc = "`com.atproto.repo.describeRepo`"]
+#[doc = "Get information about the repo, including the list of collections."]
 #[async_trait::async_trait]
 pub trait DescribeRepo: crate::xrpc::XrpcClient {
     async fn describe_repo(
@@ -20,15 +20,13 @@ pub trait DescribeRepo: crate::xrpc::XrpcClient {
         serde_json::from_slice(&body).map_err(|e| e.into())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Parameters {
-    /// The handle or DID of the repo.
+    #[doc = "The handle or DID of the repo."]
     pub repo: String,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Output {
     pub collections: Vec<String>,
@@ -37,7 +35,6 @@ pub struct Output {
     pub handle: String,
     pub handle_is_correct: bool,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {}
diff --git a/atrium-api/src/com/atproto/repo/get_record.rs b/atrium-api/src/com/atproto/repo/get_record.rs
index 5ae21e27..6161039e 100644
--- a/atrium-api/src/com/atproto/repo/get_record.rs
+++ b/atrium-api/src/com/atproto/repo/get_record.rs
@@ -1,7 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `com.atproto.repo.getRecord` namespace.
-
-/// Get a record.
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `com.atproto.repo.getRecord` namespace."]
+#[doc = "`com.atproto.repo.getRecord`"]
+#[doc = "Get a record."]
 #[async_trait::async_trait]
 pub trait GetRecord: crate::xrpc::XrpcClient {
     async fn get_record(&self, params: Parameters) -> Result<Output, Box<dyn std::error::Error>> {
@@ -17,22 +17,20 @@ pub trait GetRecord: crate::xrpc::XrpcClient {
         serde_json::from_slice(&body).map_err(|e| e.into())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Parameters {
-    /// The CID of the version of the record. If not specified, then return the most recent version.
+    #[doc = "The CID of the version of the record. If not specified, then return the most recent version."]
     #[serde(skip_serializing_if = "Option::is_none")]
     pub cid: Option<String>,
-    /// The NSID of the record collection.
+    #[doc = "The NSID of the record collection."]
     pub collection: String,
-    /// The handle or DID of the repo.
+    #[doc = "The handle or DID of the repo."]
     pub repo: String,
-    /// The key of the record.
+    #[doc = "The key of the record."]
     pub rkey: String,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Output {
     #[serde(skip_serializing_if = "Option::is_none")]
@@ -40,7 +38,6 @@ pub struct Output {
     pub uri: String,
     pub value: crate::records::Record,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {}
diff --git a/atrium-api/src/com/atproto/repo/list_records.rs b/atrium-api/src/com/atproto/repo/list_records.rs
index a4b1f161..374ee03a 100644
--- a/atrium-api/src/com/atproto/repo/list_records.rs
+++ b/atrium-api/src/com/atproto/repo/list_records.rs
@@ -1,7 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `com.atproto.repo.listRecords` namespace.
-
-/// List a range of records in a collection.
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `com.atproto.repo.listRecords` namespace."]
+#[doc = "`com.atproto.repo.listRecords`"]
+#[doc = "List a range of records in a collection."]
 #[async_trait::async_trait]
 pub trait ListRecords: crate::xrpc::XrpcClient {
     async fn list_records(&self, params: Parameters) -> Result<Output, Box<dyn std::error::Error>> {
@@ -17,44 +17,40 @@ pub trait ListRecords: crate::xrpc::XrpcClient {
         serde_json::from_slice(&body).map_err(|e| e.into())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Parameters {
-    /// The NSID of the record type.
+    #[doc = "The NSID of the record type."]
     pub collection: String,
     #[serde(skip_serializing_if = "Option::is_none")]
     pub cursor: Option<String>,
-    /// The number of records to return.
+    #[doc = "The number of records to return."]
     #[serde(skip_serializing_if = "Option::is_none")]
     pub limit: Option<i32>,
-    /// The handle or DID of the repo.
+    #[doc = "The handle or DID of the repo."]
     pub repo: String,
-    /// Reverse the order of the returned records?
+    #[doc = "Reverse the order of the returned records?"]
     #[serde(skip_serializing_if = "Option::is_none")]
     pub reverse: Option<bool>,
-    /// DEPRECATED: The highest sort-ordered rkey to stop at (exclusive)
+    #[doc = "DEPRECATED: The highest sort-ordered rkey to stop at (exclusive)"]
     #[serde(skip_serializing_if = "Option::is_none")]
     pub rkey_end: Option<String>,
-    /// DEPRECATED: The lowest sort-ordered rkey to start from (exclusive)
+    #[doc = "DEPRECATED: The lowest sort-ordered rkey to start from (exclusive)"]
     #[serde(skip_serializing_if = "Option::is_none")]
     pub rkey_start: Option<String>,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Output {
     #[serde(skip_serializing_if = "Option::is_none")]
     pub cursor: Option<String>,
     pub records: Vec<Record>,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {}
-
-// com.atproto.repo.listRecords#record
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[doc = "`com.atproto.repo.listRecords#record`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Record {
     pub cid: String,
diff --git a/atrium-api/src/com/atproto/repo/put_record.rs b/atrium-api/src/com/atproto/repo/put_record.rs
index 82a7f947..f84d5e42 100644
--- a/atrium-api/src/com/atproto/repo/put_record.rs
+++ b/atrium-api/src/com/atproto/repo/put_record.rs
@@ -1,7 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `com.atproto.repo.putRecord` namespace.
-
-/// Write a record, creating or updating it as needed.
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `com.atproto.repo.putRecord` namespace."]
+#[doc = "`com.atproto.repo.putRecord`"]
+#[doc = "Write a record, creating or updating it as needed."]
 #[async_trait::async_trait]
 pub trait PutRecord: crate::xrpc::XrpcClient {
     async fn put_record(&self, input: Input) -> Result<Output, Box<dyn std::error::Error>> {
@@ -17,37 +17,34 @@ pub trait PutRecord: crate::xrpc::XrpcClient {
         serde_json::from_slice(&body).map_err(|e| e.into())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Input {
-    /// The NSID of the record collection.
+    #[doc = "The NSID of the record collection."]
     pub collection: String,
-    /// The record to write.
+    #[doc = "The record to write."]
     pub record: crate::records::Record,
-    /// The handle or DID of the repo.
+    #[doc = "The handle or DID of the repo."]
     pub repo: String,
-    /// The key of the record.
+    #[doc = "The key of the record."]
     pub rkey: String,
-    /// Compare and swap with the previous commit by cid.
+    #[doc = "Compare and swap with the previous commit by cid."]
     #[serde(skip_serializing_if = "Option::is_none")]
     pub swap_commit: Option<String>,
-    /// Compare and swap with the previous record by cid.
+    #[doc = "Compare and swap with the previous record by cid."]
     #[serde(skip_serializing_if = "Option::is_none")]
     pub swap_record: Option<String>,
-    /// Validate the record?
+    #[doc = "Validate the record?"]
     #[serde(skip_serializing_if = "Option::is_none")]
     pub validate: Option<bool>,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Output {
     pub cid: String,
     pub uri: String,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {
     InvalidSwap(Option<String>),
diff --git a/atrium-api/src/com/atproto/repo/strong_ref.rs b/atrium-api/src/com/atproto/repo/strong_ref.rs
index 0e0459bd..f50636af 100644
--- a/atrium-api/src/com/atproto/repo/strong_ref.rs
+++ b/atrium-api/src/com/atproto/repo/strong_ref.rs
@@ -1,9 +1,8 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `com.atproto.repo.strongRef` namespace.
-//! A URI with a content-hash fingerprint.
-
-// com.atproto.repo.strongRef
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `com.atproto.repo.strongRef` namespace."]
+#![doc = "A URI with a content-hash fingerprint."]
+#[doc = "`com.atproto.repo.strongRef`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Main {
     pub cid: String,
diff --git a/atrium-api/src/com/atproto/repo/upload_blob.rs b/atrium-api/src/com/atproto/repo/upload_blob.rs
index 12f3bebc..372e7417 100644
--- a/atrium-api/src/com/atproto/repo/upload_blob.rs
+++ b/atrium-api/src/com/atproto/repo/upload_blob.rs
@@ -1,7 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `com.atproto.repo.uploadBlob` namespace.
-
-/// Upload a new blob to be added to repo in a later request.
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `com.atproto.repo.uploadBlob` namespace."]
+#[doc = "`com.atproto.repo.uploadBlob`"]
+#[doc = "Upload a new blob to be added to repo in a later request."]
 #[async_trait::async_trait]
 pub trait UploadBlob: crate::xrpc::XrpcClient {
     async fn upload_blob(&self, input: Vec<u8>) -> Result<Output, Box<dyn std::error::Error>> {
@@ -17,13 +17,11 @@ pub trait UploadBlob: crate::xrpc::XrpcClient {
         serde_json::from_slice(&body).map_err(|e| e.into())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Output {
     pub blob: crate::blob::BlobRef,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {}
diff --git a/atrium-api/src/com/atproto/server.rs b/atrium-api/src/com/atproto/server.rs
index 2f992429..6ab7ae84 100644
--- a/atrium-api/src/com/atproto/server.rs
+++ b/atrium-api/src/com/atproto/server.rs
@@ -1,4 +1,4 @@
-// This file is generated by atrium-codegen. Do not edit.
+// This file is generated by atrium-codegen. DO NOT EDIT.
 pub mod create_account;
 pub mod create_app_password;
 pub mod create_invite_code;
diff --git a/atrium-api/src/com/atproto/server/create_account.rs b/atrium-api/src/com/atproto/server/create_account.rs
index a759d309..729753b2 100644
--- a/atrium-api/src/com/atproto/server/create_account.rs
+++ b/atrium-api/src/com/atproto/server/create_account.rs
@@ -1,7 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `com.atproto.server.createAccount` namespace.
-
-/// Create an account.
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `com.atproto.server.createAccount` namespace."]
+#[doc = "`com.atproto.server.createAccount`"]
+#[doc = "Create an account."]
 #[async_trait::async_trait]
 pub trait CreateAccount: crate::xrpc::XrpcClient {
     async fn create_account(&self, input: Input) -> Result<Output, Box<dyn std::error::Error>> {
@@ -17,8 +17,7 @@ pub trait CreateAccount: crate::xrpc::XrpcClient {
         serde_json::from_slice(&body).map_err(|e| e.into())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Input {
     pub email: String,
@@ -29,8 +28,7 @@ pub struct Input {
     #[serde(skip_serializing_if = "Option::is_none")]
     pub recovery_key: Option<String>,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Output {
     pub access_jwt: String,
@@ -38,8 +36,7 @@ pub struct Output {
     pub handle: String,
     pub refresh_jwt: String,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {
     InvalidHandle(Option<String>),
diff --git a/atrium-api/src/com/atproto/server/create_app_password.rs b/atrium-api/src/com/atproto/server/create_app_password.rs
index 859885bb..d6af9304 100644
--- a/atrium-api/src/com/atproto/server/create_app_password.rs
+++ b/atrium-api/src/com/atproto/server/create_app_password.rs
@@ -1,7 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `com.atproto.server.createAppPassword` namespace.
-
-/// Create an app-specific password.
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `com.atproto.server.createAppPassword` namespace."]
+#[doc = "`com.atproto.server.createAppPassword`"]
+#[doc = "Create an app-specific password."]
 #[async_trait::async_trait]
 pub trait CreateAppPassword: crate::xrpc::XrpcClient {
     async fn create_app_password(
@@ -20,23 +20,19 @@ pub trait CreateAppPassword: crate::xrpc::XrpcClient {
         serde_json::from_slice(&body).map_err(|e| e.into())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Input {
     pub name: String,
 }
-
 pub type Output = AppPassword;
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {
     AccountTakedown(Option<String>),
 }
-
-// com.atproto.server.createAppPassword#appPassword
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[doc = "`com.atproto.server.createAppPassword#appPassword`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct AppPassword {
     pub created_at: String,
diff --git a/atrium-api/src/com/atproto/server/create_invite_code.rs b/atrium-api/src/com/atproto/server/create_invite_code.rs
index 76cea785..41db5163 100644
--- a/atrium-api/src/com/atproto/server/create_invite_code.rs
+++ b/atrium-api/src/com/atproto/server/create_invite_code.rs
@@ -1,7 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `com.atproto.server.createInviteCode` namespace.
-
-/// Create an invite code.
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `com.atproto.server.createInviteCode` namespace."]
+#[doc = "`com.atproto.server.createInviteCode`"]
+#[doc = "Create an invite code."]
 #[async_trait::async_trait]
 pub trait CreateInviteCode: crate::xrpc::XrpcClient {
     async fn create_invite_code(&self, input: Input) -> Result<Output, Box<dyn std::error::Error>> {
@@ -17,21 +17,18 @@ pub trait CreateInviteCode: crate::xrpc::XrpcClient {
         serde_json::from_slice(&body).map_err(|e| e.into())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Input {
     #[serde(skip_serializing_if = "Option::is_none")]
     pub for_account: Option<String>,
     pub use_count: i32,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Output {
     pub code: String,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {}
diff --git a/atrium-api/src/com/atproto/server/create_invite_codes.rs b/atrium-api/src/com/atproto/server/create_invite_codes.rs
index 512eb101..5dd4a1b4 100644
--- a/atrium-api/src/com/atproto/server/create_invite_codes.rs
+++ b/atrium-api/src/com/atproto/server/create_invite_codes.rs
@@ -1,7 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `com.atproto.server.createInviteCodes` namespace.
-
-/// Create an invite code.
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `com.atproto.server.createInviteCodes` namespace."]
+#[doc = "`com.atproto.server.createInviteCodes`"]
+#[doc = "Create an invite code."]
 #[async_trait::async_trait]
 pub trait CreateInviteCodes: crate::xrpc::XrpcClient {
     async fn create_invite_codes(
@@ -20,8 +20,7 @@ pub trait CreateInviteCodes: crate::xrpc::XrpcClient {
         serde_json::from_slice(&body).map_err(|e| e.into())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Input {
     pub code_count: i32,
@@ -29,19 +28,16 @@ pub struct Input {
     pub for_accounts: Option<Vec<String>>,
     pub use_count: i32,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Output {
     pub codes: Vec<AccountCodes>,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {}
-
-// com.atproto.server.createInviteCodes#accountCodes
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[doc = "`com.atproto.server.createInviteCodes#accountCodes`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct AccountCodes {
     pub account: String,
diff --git a/atrium-api/src/com/atproto/server/create_session.rs b/atrium-api/src/com/atproto/server/create_session.rs
index c2bc14e4..96d20423 100644
--- a/atrium-api/src/com/atproto/server/create_session.rs
+++ b/atrium-api/src/com/atproto/server/create_session.rs
@@ -1,7 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `com.atproto.server.createSession` namespace.
-
-/// Create an authentication session.
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `com.atproto.server.createSession` namespace."]
+#[doc = "`com.atproto.server.createSession`"]
+#[doc = "Create an authentication session."]
 #[async_trait::async_trait]
 pub trait CreateSession: crate::xrpc::XrpcClient {
     async fn create_session(&self, input: Input) -> Result<Output, Box<dyn std::error::Error>> {
@@ -17,16 +17,14 @@ pub trait CreateSession: crate::xrpc::XrpcClient {
         serde_json::from_slice(&body).map_err(|e| e.into())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Input {
-    /// Handle or other identifier supported by the server for the authenticating user.
+    #[doc = "Handle or other identifier supported by the server for the authenticating user."]
     pub identifier: String,
     pub password: String,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Output {
     pub access_jwt: String,
@@ -36,8 +34,7 @@ pub struct Output {
     pub handle: String,
     pub refresh_jwt: String,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {
     AccountTakedown(Option<String>),
diff --git a/atrium-api/src/com/atproto/server/defs.rs b/atrium-api/src/com/atproto/server/defs.rs
index 5861623b..6bf5f5fc 100644
--- a/atrium-api/src/com/atproto/server/defs.rs
+++ b/atrium-api/src/com/atproto/server/defs.rs
@@ -1,8 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `com.atproto.server.defs` namespace.
-
-// com.atproto.server.defs#inviteCode
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `com.atproto.server.defs` namespace."]
+#[doc = "`com.atproto.server.defs#inviteCode`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct InviteCode {
     pub available: i32,
@@ -13,9 +12,8 @@ pub struct InviteCode {
     pub for_account: String,
     pub uses: Vec<InviteCodeUse>,
 }
-
-// com.atproto.server.defs#inviteCodeUse
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[doc = "`com.atproto.server.defs#inviteCodeUse`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct InviteCodeUse {
     pub used_at: String,
diff --git a/atrium-api/src/com/atproto/server/delete_account.rs b/atrium-api/src/com/atproto/server/delete_account.rs
index c815e328..dc74bfd3 100644
--- a/atrium-api/src/com/atproto/server/delete_account.rs
+++ b/atrium-api/src/com/atproto/server/delete_account.rs
@@ -1,7 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `com.atproto.server.deleteAccount` namespace.
-
-/// Delete a user account with a token and password.
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `com.atproto.server.deleteAccount` namespace."]
+#[doc = "`com.atproto.server.deleteAccount`"]
+#[doc = "Delete a user account with a token and password."]
 #[async_trait::async_trait]
 pub trait DeleteAccount: crate::xrpc::XrpcClient {
     async fn delete_account(&self, input: Input) -> Result<(), Box<dyn std::error::Error>> {
@@ -17,16 +17,14 @@ pub trait DeleteAccount: crate::xrpc::XrpcClient {
         Ok(())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Input {
     pub did: String,
     pub password: String,
     pub token: String,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {
     ExpiredToken(Option<String>),
diff --git a/atrium-api/src/com/atproto/server/delete_session.rs b/atrium-api/src/com/atproto/server/delete_session.rs
index a5e75711..d616bd82 100644
--- a/atrium-api/src/com/atproto/server/delete_session.rs
+++ b/atrium-api/src/com/atproto/server/delete_session.rs
@@ -1,23 +1,22 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `com.atproto.server.deleteSession` namespace.
-
-/// Delete the current session.
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `com.atproto.server.deleteSession` namespace."]
+#[doc = "`com.atproto.server.deleteSession`"]
+#[doc = "Delete the current session."]
 #[async_trait::async_trait]
 pub trait DeleteSession: crate::xrpc::XrpcClient {
-    async fn delete_session(&self, input: Vec<u8>) -> Result<(), Box<dyn std::error::Error>> {
+    async fn delete_session(&self) -> Result<(), Box<dyn std::error::Error>> {
         let _ = crate::xrpc::XrpcClient::send::<Error>(
             self,
             http::Method::POST,
             "com.atproto.server.deleteSession",
             None,
-            Some(input),
+            None,
             None,
         )
         .await?;
         Ok(())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {}
diff --git a/atrium-api/src/com/atproto/server/describe_server.rs b/atrium-api/src/com/atproto/server/describe_server.rs
index d1f20b3f..320958db 100644
--- a/atrium-api/src/com/atproto/server/describe_server.rs
+++ b/atrium-api/src/com/atproto/server/describe_server.rs
@@ -1,7 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `com.atproto.server.describeServer` namespace.
-
-/// Get a document describing the service's accounts configuration.
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `com.atproto.server.describeServer` namespace."]
+#[doc = "`com.atproto.server.describeServer`"]
+#[doc = "Get a document describing the service's accounts configuration."]
 #[async_trait::async_trait]
 pub trait DescribeServer: crate::xrpc::XrpcClient {
     async fn describe_server(&self) -> Result<Output, Box<dyn std::error::Error>> {
@@ -17,8 +17,7 @@ pub trait DescribeServer: crate::xrpc::XrpcClient {
         serde_json::from_slice(&body).map_err(|e| e.into())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Output {
     pub available_user_domains: Vec<String>,
@@ -27,13 +26,11 @@ pub struct Output {
     #[serde(skip_serializing_if = "Option::is_none")]
     pub links: Option<Links>,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {}
-
-// com.atproto.server.describeServer#links
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[doc = "`com.atproto.server.describeServer#links`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Links {
     #[serde(skip_serializing_if = "Option::is_none")]
diff --git a/atrium-api/src/com/atproto/server/get_account_invite_codes.rs b/atrium-api/src/com/atproto/server/get_account_invite_codes.rs
index 1d35decd..2c8a1ac5 100644
--- a/atrium-api/src/com/atproto/server/get_account_invite_codes.rs
+++ b/atrium-api/src/com/atproto/server/get_account_invite_codes.rs
@@ -1,7 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `com.atproto.server.getAccountInviteCodes` namespace.
-
-/// Get all invite codes for a given account
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `com.atproto.server.getAccountInviteCodes` namespace."]
+#[doc = "`com.atproto.server.getAccountInviteCodes`"]
+#[doc = "Get all invite codes for a given account"]
 #[async_trait::async_trait]
 pub trait GetAccountInviteCodes: crate::xrpc::XrpcClient {
     async fn get_account_invite_codes(
@@ -20,8 +20,7 @@ pub trait GetAccountInviteCodes: crate::xrpc::XrpcClient {
         serde_json::from_slice(&body).map_err(|e| e.into())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Parameters {
     #[serde(skip_serializing_if = "Option::is_none")]
@@ -29,14 +28,12 @@ pub struct Parameters {
     #[serde(skip_serializing_if = "Option::is_none")]
     pub include_used: Option<bool>,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Output {
     pub codes: Vec<crate::com::atproto::server::defs::InviteCode>,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {
     DuplicateCreate(Option<String>),
diff --git a/atrium-api/src/com/atproto/server/get_session.rs b/atrium-api/src/com/atproto/server/get_session.rs
index a882c72b..f39ab797 100644
--- a/atrium-api/src/com/atproto/server/get_session.rs
+++ b/atrium-api/src/com/atproto/server/get_session.rs
@@ -1,7 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `com.atproto.server.getSession` namespace.
-
-/// Get information about the current session.
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `com.atproto.server.getSession` namespace."]
+#[doc = "`com.atproto.server.getSession`"]
+#[doc = "Get information about the current session."]
 #[async_trait::async_trait]
 pub trait GetSession: crate::xrpc::XrpcClient {
     async fn get_session(&self) -> Result<Output, Box<dyn std::error::Error>> {
@@ -17,8 +17,7 @@ pub trait GetSession: crate::xrpc::XrpcClient {
         serde_json::from_slice(&body).map_err(|e| e.into())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Output {
     pub did: String,
@@ -26,7 +25,6 @@ pub struct Output {
     pub email: Option<String>,
     pub handle: String,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {}
diff --git a/atrium-api/src/com/atproto/server/list_app_passwords.rs b/atrium-api/src/com/atproto/server/list_app_passwords.rs
index 8045a116..d3e63845 100644
--- a/atrium-api/src/com/atproto/server/list_app_passwords.rs
+++ b/atrium-api/src/com/atproto/server/list_app_passwords.rs
@@ -1,7 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `com.atproto.server.listAppPasswords` namespace.
-
-/// List all app-specific passwords.
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `com.atproto.server.listAppPasswords` namespace."]
+#[doc = "`com.atproto.server.listAppPasswords`"]
+#[doc = "List all app-specific passwords."]
 #[async_trait::async_trait]
 pub trait ListAppPasswords: crate::xrpc::XrpcClient {
     async fn list_app_passwords(&self) -> Result<Output, Box<dyn std::error::Error>> {
@@ -17,21 +17,18 @@ pub trait ListAppPasswords: crate::xrpc::XrpcClient {
         serde_json::from_slice(&body).map_err(|e| e.into())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Output {
     pub passwords: Vec<AppPassword>,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {
     AccountTakedown(Option<String>),
 }
-
-// com.atproto.server.listAppPasswords#appPassword
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[doc = "`com.atproto.server.listAppPasswords#appPassword`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct AppPassword {
     pub created_at: String,
diff --git a/atrium-api/src/com/atproto/server/refresh_session.rs b/atrium-api/src/com/atproto/server/refresh_session.rs
index 9fa4b513..dbb0d542 100644
--- a/atrium-api/src/com/atproto/server/refresh_session.rs
+++ b/atrium-api/src/com/atproto/server/refresh_session.rs
@@ -1,24 +1,23 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `com.atproto.server.refreshSession` namespace.
-
-/// Refresh an authentication session.
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `com.atproto.server.refreshSession` namespace."]
+#[doc = "`com.atproto.server.refreshSession`"]
+#[doc = "Refresh an authentication session."]
 #[async_trait::async_trait]
 pub trait RefreshSession: crate::xrpc::XrpcClient {
-    async fn refresh_session(&self, input: Vec<u8>) -> Result<Output, Box<dyn std::error::Error>> {
+    async fn refresh_session(&self) -> Result<Output, Box<dyn std::error::Error>> {
         let body = crate::xrpc::XrpcClient::send::<Error>(
             self,
             http::Method::POST,
             "com.atproto.server.refreshSession",
             None,
-            Some(input),
+            None,
             None,
         )
         .await?;
         serde_json::from_slice(&body).map_err(|e| e.into())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Output {
     pub access_jwt: String,
@@ -26,8 +25,7 @@ pub struct Output {
     pub handle: String,
     pub refresh_jwt: String,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {
     AccountTakedown(Option<String>),
diff --git a/atrium-api/src/com/atproto/server/request_account_delete.rs b/atrium-api/src/com/atproto/server/request_account_delete.rs
index 5bccc17c..fad736d4 100644
--- a/atrium-api/src/com/atproto/server/request_account_delete.rs
+++ b/atrium-api/src/com/atproto/server/request_account_delete.rs
@@ -1,26 +1,22 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `com.atproto.server.requestAccountDelete` namespace.
-
-/// Initiate a user account deletion via email.
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `com.atproto.server.requestAccountDelete` namespace."]
+#[doc = "`com.atproto.server.requestAccountDelete`"]
+#[doc = "Initiate a user account deletion via email."]
 #[async_trait::async_trait]
 pub trait RequestAccountDelete: crate::xrpc::XrpcClient {
-    async fn request_account_delete(
-        &self,
-        input: Vec<u8>,
-    ) -> Result<(), Box<dyn std::error::Error>> {
+    async fn request_account_delete(&self) -> Result<(), Box<dyn std::error::Error>> {
         let _ = crate::xrpc::XrpcClient::send::<Error>(
             self,
             http::Method::POST,
             "com.atproto.server.requestAccountDelete",
             None,
-            Some(input),
+            None,
             None,
         )
         .await?;
         Ok(())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {}
diff --git a/atrium-api/src/com/atproto/server/request_password_reset.rs b/atrium-api/src/com/atproto/server/request_password_reset.rs
index 0296af5e..2deeb718 100644
--- a/atrium-api/src/com/atproto/server/request_password_reset.rs
+++ b/atrium-api/src/com/atproto/server/request_password_reset.rs
@@ -1,7 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `com.atproto.server.requestPasswordReset` namespace.
-
-/// Initiate a user account password reset via email.
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `com.atproto.server.requestPasswordReset` namespace."]
+#[doc = "`com.atproto.server.requestPasswordReset`"]
+#[doc = "Initiate a user account password reset via email."]
 #[async_trait::async_trait]
 pub trait RequestPasswordReset: crate::xrpc::XrpcClient {
     async fn request_password_reset(&self, input: Input) -> Result<(), Box<dyn std::error::Error>> {
@@ -17,13 +17,11 @@ pub trait RequestPasswordReset: crate::xrpc::XrpcClient {
         Ok(())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Input {
     pub email: String,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {}
diff --git a/atrium-api/src/com/atproto/server/reset_password.rs b/atrium-api/src/com/atproto/server/reset_password.rs
index ffc93771..daa257e8 100644
--- a/atrium-api/src/com/atproto/server/reset_password.rs
+++ b/atrium-api/src/com/atproto/server/reset_password.rs
@@ -1,7 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `com.atproto.server.resetPassword` namespace.
-
-/// Reset a user account password using a token.
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `com.atproto.server.resetPassword` namespace."]
+#[doc = "`com.atproto.server.resetPassword`"]
+#[doc = "Reset a user account password using a token."]
 #[async_trait::async_trait]
 pub trait ResetPassword: crate::xrpc::XrpcClient {
     async fn reset_password(&self, input: Input) -> Result<(), Box<dyn std::error::Error>> {
@@ -17,15 +17,13 @@ pub trait ResetPassword: crate::xrpc::XrpcClient {
         Ok(())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Input {
     pub password: String,
     pub token: String,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {
     ExpiredToken(Option<String>),
diff --git a/atrium-api/src/com/atproto/server/revoke_app_password.rs b/atrium-api/src/com/atproto/server/revoke_app_password.rs
index d97ccc99..f7d49fdf 100644
--- a/atrium-api/src/com/atproto/server/revoke_app_password.rs
+++ b/atrium-api/src/com/atproto/server/revoke_app_password.rs
@@ -1,7 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `com.atproto.server.revokeAppPassword` namespace.
-
-/// Revoke an app-specific password by name.
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `com.atproto.server.revokeAppPassword` namespace."]
+#[doc = "`com.atproto.server.revokeAppPassword`"]
+#[doc = "Revoke an app-specific password by name."]
 #[async_trait::async_trait]
 pub trait RevokeAppPassword: crate::xrpc::XrpcClient {
     async fn revoke_app_password(&self, input: Input) -> Result<(), Box<dyn std::error::Error>> {
@@ -17,13 +17,11 @@ pub trait RevokeAppPassword: crate::xrpc::XrpcClient {
         Ok(())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Input {
     pub name: String,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {}
diff --git a/atrium-api/src/com/atproto/sync.rs b/atrium-api/src/com/atproto/sync.rs
index 566bed24..c19ec006 100644
--- a/atrium-api/src/com/atproto/sync.rs
+++ b/atrium-api/src/com/atproto/sync.rs
@@ -1,4 +1,4 @@
-// This file is generated by atrium-codegen. Do not edit.
+// This file is generated by atrium-codegen. DO NOT EDIT.
 pub mod get_blob;
 pub mod get_blocks;
 pub mod get_checkout;
diff --git a/atrium-api/src/com/atproto/sync/get_blob.rs b/atrium-api/src/com/atproto/sync/get_blob.rs
index 7673570e..7e740183 100644
--- a/atrium-api/src/com/atproto/sync/get_blob.rs
+++ b/atrium-api/src/com/atproto/sync/get_blob.rs
@@ -1,11 +1,11 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `com.atproto.sync.getBlob` namespace.
-
-/// Get a blob associated with a given repo.
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `com.atproto.sync.getBlob` namespace."]
+#[doc = "`com.atproto.sync.getBlob`"]
+#[doc = "Get a blob associated with a given repo."]
 #[async_trait::async_trait]
 pub trait GetBlob: crate::xrpc::XrpcClient {
     async fn get_blob(&self, params: Parameters) -> Result<(), Box<dyn std::error::Error>> {
-        let body = crate::xrpc::XrpcClient::send::<Error>(
+        let _ = crate::xrpc::XrpcClient::send::<Error>(
             self,
             http::Method::GET,
             "com.atproto.sync.getBlob",
@@ -14,19 +14,17 @@ pub trait GetBlob: crate::xrpc::XrpcClient {
             None,
         )
         .await?;
-        serde_json::from_slice(&body).map_err(|e| e.into())
+        Ok(())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Parameters {
-    /// The CID of the blob to fetch
+    #[doc = "The CID of the blob to fetch"]
     pub cid: String,
-    /// The DID of the repo.
+    #[doc = "The DID of the repo."]
     pub did: String,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {}
diff --git a/atrium-api/src/com/atproto/sync/get_blocks.rs b/atrium-api/src/com/atproto/sync/get_blocks.rs
index 4242effb..76b39cbd 100644
--- a/atrium-api/src/com/atproto/sync/get_blocks.rs
+++ b/atrium-api/src/com/atproto/sync/get_blocks.rs
@@ -1,11 +1,11 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `com.atproto.sync.getBlocks` namespace.
-
-/// Gets blocks from a given repo.
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `com.atproto.sync.getBlocks` namespace."]
+#[doc = "`com.atproto.sync.getBlocks`"]
+#[doc = "Gets blocks from a given repo."]
 #[async_trait::async_trait]
 pub trait GetBlocks: crate::xrpc::XrpcClient {
     async fn get_blocks(&self, params: Parameters) -> Result<(), Box<dyn std::error::Error>> {
-        let body = crate::xrpc::XrpcClient::send::<Error>(
+        let _ = crate::xrpc::XrpcClient::send::<Error>(
             self,
             http::Method::GET,
             "com.atproto.sync.getBlocks",
@@ -14,18 +14,16 @@ pub trait GetBlocks: crate::xrpc::XrpcClient {
             None,
         )
         .await?;
-        serde_json::from_slice(&body).map_err(|e| e.into())
+        Ok(())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Parameters {
     pub cids: Vec<String>,
-    /// The DID of the repo.
+    #[doc = "The DID of the repo."]
     pub did: String,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {}
diff --git a/atrium-api/src/com/atproto/sync/get_checkout.rs b/atrium-api/src/com/atproto/sync/get_checkout.rs
index b16c0118..8bbba08d 100644
--- a/atrium-api/src/com/atproto/sync/get_checkout.rs
+++ b/atrium-api/src/com/atproto/sync/get_checkout.rs
@@ -1,11 +1,11 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `com.atproto.sync.getCheckout` namespace.
-
-/// Gets the repo state.
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `com.atproto.sync.getCheckout` namespace."]
+#[doc = "`com.atproto.sync.getCheckout`"]
+#[doc = "Gets the repo state."]
 #[async_trait::async_trait]
 pub trait GetCheckout: crate::xrpc::XrpcClient {
     async fn get_checkout(&self, params: Parameters) -> Result<(), Box<dyn std::error::Error>> {
-        let body = crate::xrpc::XrpcClient::send::<Error>(
+        let _ = crate::xrpc::XrpcClient::send::<Error>(
             self,
             http::Method::GET,
             "com.atproto.sync.getCheckout",
@@ -14,20 +14,18 @@ pub trait GetCheckout: crate::xrpc::XrpcClient {
             None,
         )
         .await?;
-        serde_json::from_slice(&body).map_err(|e| e.into())
+        Ok(())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Parameters {
-    /// The commit to get the checkout from. Defaults to current HEAD.
+    #[doc = "The commit to get the checkout from. Defaults to current HEAD."]
     #[serde(skip_serializing_if = "Option::is_none")]
     pub commit: Option<String>,
-    /// The DID of the repo.
+    #[doc = "The DID of the repo."]
     pub did: String,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {}
diff --git a/atrium-api/src/com/atproto/sync/get_commit_path.rs b/atrium-api/src/com/atproto/sync/get_commit_path.rs
index 1b5bef35..32f344bc 100644
--- a/atrium-api/src/com/atproto/sync/get_commit_path.rs
+++ b/atrium-api/src/com/atproto/sync/get_commit_path.rs
@@ -1,7 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `com.atproto.sync.getCommitPath` namespace.
-
-/// Gets the path of repo commits
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `com.atproto.sync.getCommitPath` namespace."]
+#[doc = "`com.atproto.sync.getCommitPath`"]
+#[doc = "Gets the path of repo commits"]
 #[async_trait::async_trait]
 pub trait GetCommitPath: crate::xrpc::XrpcClient {
     async fn get_commit_path(
@@ -20,26 +20,23 @@ pub trait GetCommitPath: crate::xrpc::XrpcClient {
         serde_json::from_slice(&body).map_err(|e| e.into())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Parameters {
-    /// The DID of the repo.
+    #[doc = "The DID of the repo."]
     pub did: String,
-    /// The earliest commit to start from
+    #[doc = "The earliest commit to start from"]
     #[serde(skip_serializing_if = "Option::is_none")]
     pub earliest: Option<String>,
-    /// The most recent commit
+    #[doc = "The most recent commit"]
     #[serde(skip_serializing_if = "Option::is_none")]
     pub latest: Option<String>,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Output {
     pub commits: Vec<String>,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {}
diff --git a/atrium-api/src/com/atproto/sync/get_head.rs b/atrium-api/src/com/atproto/sync/get_head.rs
index a03b1aec..91cb0ee7 100644
--- a/atrium-api/src/com/atproto/sync/get_head.rs
+++ b/atrium-api/src/com/atproto/sync/get_head.rs
@@ -1,7 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `com.atproto.sync.getHead` namespace.
-
-/// Gets the current HEAD CID of a repo.
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `com.atproto.sync.getHead` namespace."]
+#[doc = "`com.atproto.sync.getHead`"]
+#[doc = "Gets the current HEAD CID of a repo."]
 #[async_trait::async_trait]
 pub trait GetHead: crate::xrpc::XrpcClient {
     async fn get_head(&self, params: Parameters) -> Result<Output, Box<dyn std::error::Error>> {
@@ -17,20 +17,17 @@ pub trait GetHead: crate::xrpc::XrpcClient {
         serde_json::from_slice(&body).map_err(|e| e.into())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Parameters {
-    /// The DID of the repo.
+    #[doc = "The DID of the repo."]
     pub did: String,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Output {
     pub root: String,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {}
diff --git a/atrium-api/src/com/atproto/sync/get_record.rs b/atrium-api/src/com/atproto/sync/get_record.rs
index c2a557c5..c396210e 100644
--- a/atrium-api/src/com/atproto/sync/get_record.rs
+++ b/atrium-api/src/com/atproto/sync/get_record.rs
@@ -1,11 +1,11 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `com.atproto.sync.getRecord` namespace.
-
-/// Gets blocks needed for existence or non-existence of record.
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `com.atproto.sync.getRecord` namespace."]
+#[doc = "`com.atproto.sync.getRecord`"]
+#[doc = "Gets blocks needed for existence or non-existence of record."]
 #[async_trait::async_trait]
 pub trait GetRecord: crate::xrpc::XrpcClient {
     async fn get_record(&self, params: Parameters) -> Result<(), Box<dyn std::error::Error>> {
-        let body = crate::xrpc::XrpcClient::send::<Error>(
+        let _ = crate::xrpc::XrpcClient::send::<Error>(
             self,
             http::Method::GET,
             "com.atproto.sync.getRecord",
@@ -14,22 +14,20 @@ pub trait GetRecord: crate::xrpc::XrpcClient {
             None,
         )
         .await?;
-        serde_json::from_slice(&body).map_err(|e| e.into())
+        Ok(())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Parameters {
     pub collection: String,
-    /// An optional past commit CID.
+    #[doc = "An optional past commit CID."]
     #[serde(skip_serializing_if = "Option::is_none")]
     pub commit: Option<String>,
-    /// The DID of the repo.
+    #[doc = "The DID of the repo."]
     pub did: String,
     pub rkey: String,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {}
diff --git a/atrium-api/src/com/atproto/sync/get_repo.rs b/atrium-api/src/com/atproto/sync/get_repo.rs
index d567a879..3f3f6282 100644
--- a/atrium-api/src/com/atproto/sync/get_repo.rs
+++ b/atrium-api/src/com/atproto/sync/get_repo.rs
@@ -1,11 +1,11 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `com.atproto.sync.getRepo` namespace.
-
-/// Gets the repo state.
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `com.atproto.sync.getRepo` namespace."]
+#[doc = "`com.atproto.sync.getRepo`"]
+#[doc = "Gets the repo state."]
 #[async_trait::async_trait]
 pub trait GetRepo: crate::xrpc::XrpcClient {
     async fn get_repo(&self, params: Parameters) -> Result<(), Box<dyn std::error::Error>> {
-        let body = crate::xrpc::XrpcClient::send::<Error>(
+        let _ = crate::xrpc::XrpcClient::send::<Error>(
             self,
             http::Method::GET,
             "com.atproto.sync.getRepo",
@@ -14,23 +14,21 @@ pub trait GetRepo: crate::xrpc::XrpcClient {
             None,
         )
         .await?;
-        serde_json::from_slice(&body).map_err(|e| e.into())
+        Ok(())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Parameters {
-    /// The DID of the repo.
+    #[doc = "The DID of the repo."]
     pub did: String,
-    /// The earliest commit in the commit range (not inclusive)
+    #[doc = "The earliest commit in the commit range (not inclusive)"]
     #[serde(skip_serializing_if = "Option::is_none")]
     pub earliest: Option<String>,
-    /// The latest commit in the commit range (inclusive)
+    #[doc = "The latest commit in the commit range (inclusive)"]
     #[serde(skip_serializing_if = "Option::is_none")]
     pub latest: Option<String>,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {}
diff --git a/atrium-api/src/com/atproto/sync/list_blobs.rs b/atrium-api/src/com/atproto/sync/list_blobs.rs
index bb498d07..16e0f01c 100644
--- a/atrium-api/src/com/atproto/sync/list_blobs.rs
+++ b/atrium-api/src/com/atproto/sync/list_blobs.rs
@@ -1,7 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `com.atproto.sync.listBlobs` namespace.
-
-/// List blob cids for some range of commits
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `com.atproto.sync.listBlobs` namespace."]
+#[doc = "`com.atproto.sync.listBlobs`"]
+#[doc = "List blob cids for some range of commits"]
 #[async_trait::async_trait]
 pub trait ListBlobs: crate::xrpc::XrpcClient {
     async fn list_blobs(&self, params: Parameters) -> Result<Output, Box<dyn std::error::Error>> {
@@ -17,26 +17,23 @@ pub trait ListBlobs: crate::xrpc::XrpcClient {
         serde_json::from_slice(&body).map_err(|e| e.into())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Parameters {
-    /// The DID of the repo.
+    #[doc = "The DID of the repo."]
     pub did: String,
-    /// The earliest commit to start from
+    #[doc = "The earliest commit to start from"]
     #[serde(skip_serializing_if = "Option::is_none")]
     pub earliest: Option<String>,
-    /// The most recent commit
+    #[doc = "The most recent commit"]
     #[serde(skip_serializing_if = "Option::is_none")]
     pub latest: Option<String>,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Output {
     pub cids: Vec<String>,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {}
diff --git a/atrium-api/src/com/atproto/sync/list_repos.rs b/atrium-api/src/com/atproto/sync/list_repos.rs
index 9a76ab75..79d106f5 100644
--- a/atrium-api/src/com/atproto/sync/list_repos.rs
+++ b/atrium-api/src/com/atproto/sync/list_repos.rs
@@ -1,7 +1,7 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `com.atproto.sync.listRepos` namespace.
-
-/// List dids and root cids of hosted repos
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `com.atproto.sync.listRepos` namespace."]
+#[doc = "`com.atproto.sync.listRepos`"]
+#[doc = "List dids and root cids of hosted repos"]
 #[async_trait::async_trait]
 pub trait ListRepos: crate::xrpc::XrpcClient {
     async fn list_repos(&self, params: Parameters) -> Result<Output, Box<dyn std::error::Error>> {
@@ -17,8 +17,7 @@ pub trait ListRepos: crate::xrpc::XrpcClient {
         serde_json::from_slice(&body).map_err(|e| e.into())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Parameters {
     #[serde(skip_serializing_if = "Option::is_none")]
@@ -26,21 +25,18 @@ pub struct Parameters {
     #[serde(skip_serializing_if = "Option::is_none")]
     pub limit: Option<i32>,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Output {
     #[serde(skip_serializing_if = "Option::is_none")]
     pub cursor: Option<String>,
     pub repos: Vec<Repo>,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {}
-
-// com.atproto.sync.listRepos#repo
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[doc = "`com.atproto.sync.listRepos#repo`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Repo {
     pub did: String,
diff --git a/atrium-api/src/com/atproto/sync/notify_of_update.rs b/atrium-api/src/com/atproto/sync/notify_of_update.rs
index 6d4e9d6e..756bd742 100644
--- a/atrium-api/src/com/atproto/sync/notify_of_update.rs
+++ b/atrium-api/src/com/atproto/sync/notify_of_update.rs
@@ -1,11 +1,11 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `com.atproto.sync.notifyOfUpdate` namespace.
-
-/// Notify a crawling service of a recent update. Often when a long break between updates causes the connection with the crawling service to break.
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `com.atproto.sync.notifyOfUpdate` namespace."]
+#[doc = "`com.atproto.sync.notifyOfUpdate`"]
+#[doc = "Notify a crawling service of a recent update. Often when a long break between updates causes the connection with the crawling service to break."]
 #[async_trait::async_trait]
 pub trait NotifyOfUpdate: crate::xrpc::XrpcClient {
     async fn notify_of_update(&self, params: Parameters) -> Result<(), Box<dyn std::error::Error>> {
-        let body = crate::xrpc::XrpcClient::send::<Error>(
+        let _ = crate::xrpc::XrpcClient::send::<Error>(
             self,
             http::Method::GET,
             "com.atproto.sync.notifyOfUpdate",
@@ -14,17 +14,15 @@ pub trait NotifyOfUpdate: crate::xrpc::XrpcClient {
             None,
         )
         .await?;
-        serde_json::from_slice(&body).map_err(|e| e.into())
+        Ok(())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Parameters {
-    /// Hostname of the service that is notifying of update.
+    #[doc = "Hostname of the service that is notifying of update."]
     pub hostname: String,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {}
diff --git a/atrium-api/src/com/atproto/sync/request_crawl.rs b/atrium-api/src/com/atproto/sync/request_crawl.rs
index 03e2bad3..817f6ea0 100644
--- a/atrium-api/src/com/atproto/sync/request_crawl.rs
+++ b/atrium-api/src/com/atproto/sync/request_crawl.rs
@@ -1,11 +1,11 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `com.atproto.sync.requestCrawl` namespace.
-
-/// Request a service to persistently crawl hosted repos.
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `com.atproto.sync.requestCrawl` namespace."]
+#[doc = "`com.atproto.sync.requestCrawl`"]
+#[doc = "Request a service to persistently crawl hosted repos."]
 #[async_trait::async_trait]
 pub trait RequestCrawl: crate::xrpc::XrpcClient {
     async fn request_crawl(&self, params: Parameters) -> Result<(), Box<dyn std::error::Error>> {
-        let body = crate::xrpc::XrpcClient::send::<Error>(
+        let _ = crate::xrpc::XrpcClient::send::<Error>(
             self,
             http::Method::GET,
             "com.atproto.sync.requestCrawl",
@@ -14,17 +14,15 @@ pub trait RequestCrawl: crate::xrpc::XrpcClient {
             None,
         )
         .await?;
-        serde_json::from_slice(&body).map_err(|e| e.into())
+        Ok(())
     }
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Parameters {
-    /// Hostname of the service that is requesting to be crawled.
+    #[doc = "Hostname of the service that is requesting to be crawled."]
     pub hostname: String,
 }
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "error", content = "message")]
 pub enum Error {}
diff --git a/atrium-api/src/com/atproto/sync/subscribe_repos.rs b/atrium-api/src/com/atproto/sync/subscribe_repos.rs
index 4f5853ab..7291cf88 100644
--- a/atrium-api/src/com/atproto/sync/subscribe_repos.rs
+++ b/atrium-api/src/com/atproto/sync/subscribe_repos.rs
@@ -1,28 +1,21 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! Definitions for the `com.atproto.sync.subscribeRepos` namespace.
-
-// com.atproto.sync.subscribeRepos
-// TODO
-
-// com.atproto.sync.subscribeRepos#commit
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "Definitions for the `com.atproto.sync.subscribeRepos` namespace."]
+#[doc = "`com.atproto.sync.subscribeRepos`"]
+#[doc = "Subscribe to repo updates"]
+pub struct SubscribeRepos;
+#[doc = "`com.atproto.sync.subscribeRepos#commit`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Commit {
-    // pub blobs: Vec<...>
-    /// CAR file containing relevant blocks
-    // pub blocks: ...,
-    // pub commit: ...,
     pub ops: Vec<RepoOp>,
-    // pub prev: ...,
     pub rebase: bool,
     pub repo: String,
     pub seq: i32,
     pub time: String,
     pub too_big: bool,
 }
-
-// com.atproto.sync.subscribeRepos#handle
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[doc = "`com.atproto.sync.subscribeRepos#handle`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Handle {
     pub did: String,
@@ -30,18 +23,16 @@ pub struct Handle {
     pub seq: i32,
     pub time: String,
 }
-
-// com.atproto.sync.subscribeRepos#info
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[doc = "`com.atproto.sync.subscribeRepos#info`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Info {
     #[serde(skip_serializing_if = "Option::is_none")]
     pub message: Option<String>,
     pub name: String,
 }
-
-// com.atproto.sync.subscribeRepos#migrate
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[doc = "`com.atproto.sync.subscribeRepos#migrate`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Migrate {
     pub did: String,
@@ -49,18 +40,15 @@ pub struct Migrate {
     pub seq: i32,
     pub time: String,
 }
-
-// com.atproto.sync.subscribeRepos#repoOp
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[doc = "`com.atproto.sync.subscribeRepos#repoOp`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct RepoOp {
     pub action: String,
-    // pub cid: ...,
     pub path: String,
 }
-
-// com.atproto.sync.subscribeRepos#tombstone
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+#[doc = "`com.atproto.sync.subscribeRepos#tombstone`"]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct Tombstone {
     pub did: String,
diff --git a/atrium-api/src/lib.rs b/atrium-api/src/lib.rs
index f30fb436..5196e593 100644
--- a/atrium-api/src/lib.rs
+++ b/atrium-api/src/lib.rs
@@ -1,8 +1,8 @@
-#![doc = include_str!("../README.md")]
+// This file is generated by atrium-codegen. DO NOT EDIT.
+# ! [doc = include_str ! ("../README.md")]
+pub mod app;
 pub mod blob;
+pub mod com;
 pub mod records;
 pub mod traits;
 pub mod xrpc;
-
-pub mod app;
-pub mod com;
diff --git a/atrium-api/src/records.rs b/atrium-api/src/records.rs
index deac9e32..05fc49b7 100644
--- a/atrium-api/src/records.rs
+++ b/atrium-api/src/records.rs
@@ -1,7 +1,6 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! A collection of ATP repository record type.
-
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "A collection of ATP repository record types."]
+#[derive(serde :: Serialize, serde :: Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(tag = "$type")]
 pub enum Record {
     #[serde(rename = "app.bsky.actor.profile")]
diff --git a/atrium-api/src/traits.rs b/atrium-api/src/traits.rs
index 336123dc..f7fe3682 100644
--- a/atrium-api/src/traits.rs
+++ b/atrium-api/src/traits.rs
@@ -1,82 +1,82 @@
-// This file is generated by atrium-codegen. Do not edit.
-//! A macro for implementing the traits of all XRPC requests.
-
+// This file is generated by atrium-codegen. DO NOT EDIT.
+#![doc = "A macro for implementing the traits of all XRPC requests."]
 #[macro_export]
 macro_rules! impl_traits {
-    ($type:ty) => {
-        impl atrium_api::app::bsky::actor::get_profile::GetProfile for $type {}
-        impl atrium_api::app::bsky::actor::get_profiles::GetProfiles for $type {}
-        impl atrium_api::app::bsky::actor::get_suggestions::GetSuggestions for $type {}
-        impl atrium_api::app::bsky::actor::search_actors::SearchActors for $type {}
-        impl atrium_api::app::bsky::actor::search_actors_typeahead::SearchActorsTypeahead for $type {}
-        impl atrium_api::app::bsky::feed::get_author_feed::GetAuthorFeed for $type {}
-        impl atrium_api::app::bsky::feed::get_likes::GetLikes for $type {}
-        impl atrium_api::app::bsky::feed::get_post_thread::GetPostThread for $type {}
-        impl atrium_api::app::bsky::feed::get_posts::GetPosts for $type {}
-        impl atrium_api::app::bsky::feed::get_reposted_by::GetRepostedBy for $type {}
-        impl atrium_api::app::bsky::feed::get_timeline::GetTimeline for $type {}
-        impl atrium_api::app::bsky::graph::get_blocks::GetBlocks for $type {}
-        impl atrium_api::app::bsky::graph::get_followers::GetFollowers for $type {}
-        impl atrium_api::app::bsky::graph::get_follows::GetFollows for $type {}
-        impl atrium_api::app::bsky::graph::get_mutes::GetMutes for $type {}
-        impl atrium_api::app::bsky::graph::mute_actor::MuteActor for $type {}
-        impl atrium_api::app::bsky::graph::unmute_actor::UnmuteActor for $type {}
-        impl atrium_api::app::bsky::notification::get_unread_count::GetUnreadCount for $type {}
-        impl atrium_api::app::bsky::notification::list_notifications::ListNotifications for $type {}
-        impl atrium_api::app::bsky::notification::update_seen::UpdateSeen for $type {}
-        impl atrium_api::app::bsky::unspecced::get_popular::GetPopular for $type {}
-        impl atrium_api::com::atproto::admin::disable_invite_codes::DisableInviteCodes for $type {}
-        impl atrium_api::com::atproto::admin::get_invite_codes::GetInviteCodes for $type {}
-        impl atrium_api::com::atproto::admin::get_moderation_action::GetModerationAction for $type {}
-        impl atrium_api::com::atproto::admin::get_moderation_actions::GetModerationActions for $type {}
-        impl atrium_api::com::atproto::admin::get_moderation_report::GetModerationReport for $type {}
-        impl atrium_api::com::atproto::admin::get_moderation_reports::GetModerationReports for $type {}
-        impl atrium_api::com::atproto::admin::get_record::GetRecord for $type {}
-        impl atrium_api::com::atproto::admin::get_repo::GetRepo for $type {}
-        impl atrium_api::com::atproto::admin::resolve_moderation_reports::ResolveModerationReports for $type {}
-        impl atrium_api::com::atproto::admin::reverse_moderation_action::ReverseModerationAction for $type {}
-        impl atrium_api::com::atproto::admin::search_repos::SearchRepos for $type {}
-        impl atrium_api::com::atproto::admin::take_moderation_action::TakeModerationAction for $type {}
-        impl atrium_api::com::atproto::admin::update_account_email::UpdateAccountEmail for $type {}
-        impl atrium_api::com::atproto::admin::update_account_handle::UpdateAccountHandle for $type {}
-        impl atrium_api::com::atproto::identity::resolve_handle::ResolveHandle for $type {}
-        impl atrium_api::com::atproto::identity::update_handle::UpdateHandle for $type {}
-        impl atrium_api::com::atproto::label::query_labels::QueryLabels for $type {}
-        impl atrium_api::com::atproto::moderation::create_report::CreateReport for $type {}
-        impl atrium_api::com::atproto::repo::apply_writes::ApplyWrites for $type {}
-        impl atrium_api::com::atproto::repo::create_record::CreateRecord for $type {}
-        impl atrium_api::com::atproto::repo::delete_record::DeleteRecord for $type {}
-        impl atrium_api::com::atproto::repo::describe_repo::DescribeRepo for $type {}
-        impl atrium_api::com::atproto::repo::get_record::GetRecord for $type {}
-        impl atrium_api::com::atproto::repo::list_records::ListRecords for $type {}
-        impl atrium_api::com::atproto::repo::put_record::PutRecord for $type {}
-        impl atrium_api::com::atproto::repo::upload_blob::UploadBlob for $type {}
-        impl atrium_api::com::atproto::server::create_account::CreateAccount for $type {}
-        impl atrium_api::com::atproto::server::create_app_password::CreateAppPassword for $type {}
-        impl atrium_api::com::atproto::server::create_invite_code::CreateInviteCode for $type {}
-        impl atrium_api::com::atproto::server::create_invite_codes::CreateInviteCodes for $type {}
-        impl atrium_api::com::atproto::server::create_session::CreateSession for $type {}
-        impl atrium_api::com::atproto::server::delete_account::DeleteAccount for $type {}
-        impl atrium_api::com::atproto::server::delete_session::DeleteSession for $type {}
-        impl atrium_api::com::atproto::server::describe_server::DescribeServer for $type {}
-        impl atrium_api::com::atproto::server::get_account_invite_codes::GetAccountInviteCodes for $type {}
-        impl atrium_api::com::atproto::server::get_session::GetSession for $type {}
-        impl atrium_api::com::atproto::server::list_app_passwords::ListAppPasswords for $type {}
-        impl atrium_api::com::atproto::server::refresh_session::RefreshSession for $type {}
-        impl atrium_api::com::atproto::server::request_account_delete::RequestAccountDelete for $type {}
-        impl atrium_api::com::atproto::server::request_password_reset::RequestPasswordReset for $type {}
-        impl atrium_api::com::atproto::server::reset_password::ResetPassword for $type {}
-        impl atrium_api::com::atproto::server::revoke_app_password::RevokeAppPassword for $type {}
-        impl atrium_api::com::atproto::sync::get_blob::GetBlob for $type {}
-        impl atrium_api::com::atproto::sync::get_blocks::GetBlocks for $type {}
-        impl atrium_api::com::atproto::sync::get_checkout::GetCheckout for $type {}
-        impl atrium_api::com::atproto::sync::get_commit_path::GetCommitPath for $type {}
-        impl atrium_api::com::atproto::sync::get_head::GetHead for $type {}
-        impl atrium_api::com::atproto::sync::get_record::GetRecord for $type {}
-        impl atrium_api::com::atproto::sync::get_repo::GetRepo for $type {}
-        impl atrium_api::com::atproto::sync::list_blobs::ListBlobs for $type {}
-        impl atrium_api::com::atproto::sync::list_repos::ListRepos for $type {}
-        impl atrium_api::com::atproto::sync::notify_of_update::NotifyOfUpdate for $type {}
-        impl atrium_api::com::atproto::sync::request_crawl::RequestCrawl for $type {}
+    ($ type : ty) => {
+        use atrium_api::{app, com};
+        impl app::bsky::actor::get_profile::GetProfile for $type {}
+        impl app::bsky::actor::get_profiles::GetProfiles for $type {}
+        impl app::bsky::actor::get_suggestions::GetSuggestions for $type {}
+        impl app::bsky::actor::search_actors::SearchActors for $type {}
+        impl app::bsky::actor::search_actors_typeahead::SearchActorsTypeahead for $type {}
+        impl app::bsky::feed::get_author_feed::GetAuthorFeed for $type {}
+        impl app::bsky::feed::get_likes::GetLikes for $type {}
+        impl app::bsky::feed::get_post_thread::GetPostThread for $type {}
+        impl app::bsky::feed::get_posts::GetPosts for $type {}
+        impl app::bsky::feed::get_reposted_by::GetRepostedBy for $type {}
+        impl app::bsky::feed::get_timeline::GetTimeline for $type {}
+        impl app::bsky::graph::get_blocks::GetBlocks for $type {}
+        impl app::bsky::graph::get_followers::GetFollowers for $type {}
+        impl app::bsky::graph::get_follows::GetFollows for $type {}
+        impl app::bsky::graph::get_mutes::GetMutes for $type {}
+        impl app::bsky::graph::mute_actor::MuteActor for $type {}
+        impl app::bsky::graph::unmute_actor::UnmuteActor for $type {}
+        impl app::bsky::notification::get_unread_count::GetUnreadCount for $type {}
+        impl app::bsky::notification::list_notifications::ListNotifications for $type {}
+        impl app::bsky::notification::update_seen::UpdateSeen for $type {}
+        impl app::bsky::unspecced::get_popular::GetPopular for $type {}
+        impl com::atproto::admin::disable_invite_codes::DisableInviteCodes for $type {}
+        impl com::atproto::admin::get_invite_codes::GetInviteCodes for $type {}
+        impl com::atproto::admin::get_moderation_action::GetModerationAction for $type {}
+        impl com::atproto::admin::get_moderation_actions::GetModerationActions for $type {}
+        impl com::atproto::admin::get_moderation_report::GetModerationReport for $type {}
+        impl com::atproto::admin::get_moderation_reports::GetModerationReports for $type {}
+        impl com::atproto::admin::get_record::GetRecord for $type {}
+        impl com::atproto::admin::get_repo::GetRepo for $type {}
+        impl com::atproto::admin::resolve_moderation_reports::ResolveModerationReports for $type {}
+        impl com::atproto::admin::reverse_moderation_action::ReverseModerationAction for $type {}
+        impl com::atproto::admin::search_repos::SearchRepos for $type {}
+        impl com::atproto::admin::take_moderation_action::TakeModerationAction for $type {}
+        impl com::atproto::admin::update_account_email::UpdateAccountEmail for $type {}
+        impl com::atproto::admin::update_account_handle::UpdateAccountHandle for $type {}
+        impl com::atproto::identity::resolve_handle::ResolveHandle for $type {}
+        impl com::atproto::identity::update_handle::UpdateHandle for $type {}
+        impl com::atproto::label::query_labels::QueryLabels for $type {}
+        impl com::atproto::moderation::create_report::CreateReport for $type {}
+        impl com::atproto::repo::apply_writes::ApplyWrites for $type {}
+        impl com::atproto::repo::create_record::CreateRecord for $type {}
+        impl com::atproto::repo::delete_record::DeleteRecord for $type {}
+        impl com::atproto::repo::describe_repo::DescribeRepo for $type {}
+        impl com::atproto::repo::get_record::GetRecord for $type {}
+        impl com::atproto::repo::list_records::ListRecords for $type {}
+        impl com::atproto::repo::put_record::PutRecord for $type {}
+        impl com::atproto::repo::upload_blob::UploadBlob for $type {}
+        impl com::atproto::server::create_account::CreateAccount for $type {}
+        impl com::atproto::server::create_app_password::CreateAppPassword for $type {}
+        impl com::atproto::server::create_invite_code::CreateInviteCode for $type {}
+        impl com::atproto::server::create_invite_codes::CreateInviteCodes for $type {}
+        impl com::atproto::server::create_session::CreateSession for $type {}
+        impl com::atproto::server::delete_account::DeleteAccount for $type {}
+        impl com::atproto::server::delete_session::DeleteSession for $type {}
+        impl com::atproto::server::describe_server::DescribeServer for $type {}
+        impl com::atproto::server::get_account_invite_codes::GetAccountInviteCodes for $type {}
+        impl com::atproto::server::get_session::GetSession for $type {}
+        impl com::atproto::server::list_app_passwords::ListAppPasswords for $type {}
+        impl com::atproto::server::refresh_session::RefreshSession for $type {}
+        impl com::atproto::server::request_account_delete::RequestAccountDelete for $type {}
+        impl com::atproto::server::request_password_reset::RequestPasswordReset for $type {}
+        impl com::atproto::server::reset_password::ResetPassword for $type {}
+        impl com::atproto::server::revoke_app_password::RevokeAppPassword for $type {}
+        impl com::atproto::sync::get_blob::GetBlob for $type {}
+        impl com::atproto::sync::get_blocks::GetBlocks for $type {}
+        impl com::atproto::sync::get_checkout::GetCheckout for $type {}
+        impl com::atproto::sync::get_commit_path::GetCommitPath for $type {}
+        impl com::atproto::sync::get_head::GetHead for $type {}
+        impl com::atproto::sync::get_record::GetRecord for $type {}
+        impl com::atproto::sync::get_repo::GetRepo for $type {}
+        impl com::atproto::sync::list_blobs::ListBlobs for $type {}
+        impl com::atproto::sync::list_repos::ListRepos for $type {}
+        impl com::atproto::sync::notify_of_update::NotifyOfUpdate for $type {}
+        impl com::atproto::sync::request_crawl::RequestCrawl for $type {}
     };
 }
diff --git a/atrium-codegen/Cargo.toml b/atrium-codegen/Cargo.toml
index 79658e67..ea87fa63 100644
--- a/atrium-codegen/Cargo.toml
+++ b/atrium-codegen/Cargo.toml
@@ -8,4 +8,7 @@ authors = ["sugyan <sugi1982+github@gmail.com>"]
 atrium-lex = { path = "../atrium-lex" }
 heck = "0.4.1"
 itertools = "0.10.5"
+proc-macro2 = "1.0.56"
+quote = "1.0.26"
 serde_json = "1.0"
+syn = { version = "2.0.15", features = ["full"] }
diff --git a/atrium-codegen/src/code_writer.rs b/atrium-codegen/src/code_writer.rs
deleted file mode 100644
index b1774ba2..00000000
--- a/atrium-codegen/src/code_writer.rs
+++ /dev/null
@@ -1,730 +0,0 @@
-use atrium_lex::lexicon::*;
-use heck::{ToPascalCase, ToSnakeCase};
-use itertools::Itertools;
-use std::collections::HashSet;
-use std::fs::File;
-use std::io::{Result, Write};
-use std::path::Path;
-use std::process::Command;
-
-#[derive(Default)]
-pub(crate) struct CodeWriter {
-    buf: Vec<u8>,
-}
-
-impl CodeWriter {
-    pub fn write_header(
-        &mut self,
-        description: Option<&String>,
-        schema_id: Option<&String>,
-    ) -> Result<()> {
-        writeln!(
-            &mut self.buf,
-            "// This file is generated by atrium-codegen. Do not edit."
-        )
-        .ok();
-        if let Some(schema_id) = schema_id {
-            writeln!(
-                &mut self.buf,
-                "//! Definitions for the `{schema_id}` namespace."
-            )?;
-        }
-        if let Some(description) = description {
-            writeln!(&mut self.buf, "//! {}", description)?;
-        }
-        Ok(())
-    }
-    pub fn write_user_type(
-        &mut self,
-        schema_id: &str,
-        name: &str,
-        def: &LexUserType,
-        is_main: bool,
-    ) -> Result<()> {
-        writeln!(&mut self.buf)?;
-        match def {
-            LexUserType::XrpcQuery(query) => self.write_query(schema_id, name, query)?,
-            LexUserType::XrpcProcedure(procedure) => {
-                self.write_procedure(schema_id, name, procedure)?
-            }
-            _ => {
-                let refname = if is_main {
-                    schema_id.to_string()
-                } else {
-                    format!("{schema_id}#{name}")
-                };
-                writeln!(&mut self.buf, "// {refname}")?;
-                let defname = if is_main {
-                    String::from("Main")
-                } else {
-                    name.to_pascal_case()
-                };
-                match def {
-                    LexUserType::Record(record) => self.write_record(record)?,
-                    LexUserType::XrpcSubscription(subscription) => {
-                        self.write_subscription(&defname, subscription)?
-                    }
-                    LexUserType::Token(token) => self.write_token(&defname, token)?,
-                    LexUserType::Object(object) => self.write_object(&defname, object)?,
-                    LexUserType::String(string) => self.write_string(&defname, string)?,
-                    _ => unimplemented!(),
-                }
-            }
-        }
-        Ok(())
-    }
-    pub fn write_ref_unions(
-        &mut self,
-        schema_id: &str,
-        ref_unions: &[(String, LexRefUnion)],
-    ) -> Result<()> {
-        for (name, ref_union) in ref_unions {
-            writeln!(&mut self.buf)?;
-            if let Some(description) = &ref_union.description {
-                writeln!(&mut self.buf, "/// {}", description)?;
-            }
-            writeln!(&mut self.buf, "#[allow(clippy::large_enum_variant)]")?;
-            writeln!(
-                &mut self.buf,
-                "#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]"
-            )?;
-            writeln!(&mut self.buf, r#"#[serde(tag = "$type")]"#)?;
-            writeln!(&mut self.buf, "pub enum {name} {{")?;
-            for r#ref in &ref_union.refs {
-                let ref_type = Self::ref_type(&LexRef {
-                    description: None,
-                    r#ref: r#ref.clone(),
-                });
-                let rename = if r#ref.starts_with('#') {
-                    format!("{schema_id}{}", r#ref)
-                } else {
-                    r#ref.clone()
-                };
-                let name = ref_type
-                    .strip_prefix("crate::")
-                    .unwrap_or(&ref_type)
-                    .split("::")
-                    .map(str::to_pascal_case)
-                    .join("");
-                writeln!(&mut self.buf, r#"    #[serde(rename = "{rename}")]"#)?;
-                writeln!(&mut self.buf, "    {name}({ref_type}),")?;
-            }
-            writeln!(&mut self.buf, "}}")?;
-        }
-        Ok(())
-    }
-    pub fn write_records(&mut self, records: &[String]) -> Result<()> {
-        writeln!(
-            &mut self.buf,
-            "//! A collection of ATP repository record type."
-        )?;
-        writeln!(&mut self.buf)?;
-        writeln!(
-            &mut self.buf,
-            "#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]"
-        )?;
-        writeln!(&mut self.buf, r#"#[serde(tag = "$type")]"#)?;
-        writeln!(&mut self.buf, "pub enum Record {{")?;
-        for r in records {
-            writeln!(&mut self.buf, r#"    #[serde(rename = "{}")]"#, r)?;
-            writeln!(
-                &mut self.buf,
-                "    {}(crate::{}::Record),",
-                r.to_pascal_case(),
-                r.split('.').map(str::to_snake_case).join("::")
-            )?;
-        }
-        writeln!(&mut self.buf, "}}")?;
-        Ok(())
-    }
-    pub fn write_traits_macro(&mut self, traits: &[String]) -> Result<()> {
-        writeln!(
-            &mut self.buf,
-            "//! A macro for implementing the traits of all XRPC requests."
-        )?;
-        writeln!(&mut self.buf)?;
-        writeln!(&mut self.buf, "#[macro_export]")?;
-        writeln!(&mut self.buf, "macro_rules! impl_traits {{")?;
-        writeln!(&mut self.buf, "    ($type:ty) => {{")?;
-        for t in traits {
-            let parts = t.split('.').collect_vec();
-            writeln!(
-                &mut self.buf,
-                "        impl atrium_api::{}::{} for $type {{}}",
-                parts.iter().map(|s| s.to_snake_case()).join("::"),
-                parts[parts.len() - 1].to_pascal_case()
-            )?;
-        }
-        writeln!(&mut self.buf, "    }};")?;
-        writeln!(&mut self.buf, "}}")?;
-        Ok(())
-    }
-    pub fn write_mods(&mut self, mods: &[String]) -> Result<()> {
-        for m in mods {
-            if m == "lib" {
-                continue;
-            }
-            writeln!(&mut self.buf, "pub mod {m};")?;
-        }
-        Ok(())
-    }
-    pub fn write_to_file(&mut self, filepath: &Path) -> Result<()> {
-        let mut file = File::create(filepath)?;
-        file.write_all(&self.buf)?;
-        match Command::new("rustfmt")
-            .arg("--edition")
-            .arg("2021")
-            .arg(filepath)
-            .status()
-        {
-            Ok(status) if status.success() => {}
-            _ => {
-                eprintln!("Failed to run rustfmt on {}", filepath.display());
-            }
-        }
-        Ok(())
-    }
-
-    fn write_record(&mut self, record: &LexRecord) -> Result<()> {
-        if let Some(description) = &record.description {
-            writeln!(&mut self.buf, "/// {}", description)?;
-        }
-        let LexRecordRecord::Object(object) = &record.record;
-        self.write_object("Record", object)?;
-        Ok(())
-    }
-    fn write_query(&mut self, schema_id: &str, name: &str, query: &LexXrpcQuery) -> Result<()> {
-        if let Some(description) = &query.description {
-            writeln!(&mut self.buf, "/// {}", description)?;
-        }
-        let has_params = query.parameters.is_some();
-        let has_output = query.output.as_ref().map_or(false, |o| o.schema.is_some());
-        writeln!(&mut self.buf, "#[async_trait::async_trait]")?;
-        writeln!(
-            &mut self.buf,
-            "pub trait {}: crate::xrpc::XrpcClient {{",
-            name.to_pascal_case()
-        )?;
-        writeln!(
-            &mut self.buf,
-            "    async fn {}(&self{}) -> Result<{}, Box<dyn std::error::Error>> {{",
-            name.to_snake_case(),
-            if has_params {
-                ", params: Parameters"
-            } else {
-                ""
-            },
-            if has_output { "Output" } else { "()" }
-        )?;
-        writeln!(
-            &mut self.buf,
-            "        let body = crate::xrpc::XrpcClient::send::<Error>(",
-        )?;
-        writeln!(&mut self.buf, "            self,")?;
-        writeln!(&mut self.buf, "            http::Method::GET,")?;
-        writeln!(&mut self.buf, "            {schema_id:?},")?;
-        writeln!(
-            &mut self.buf,
-            "            {},",
-            if has_params {
-                "Some(serde_urlencoded::to_string(&params)?)"
-            } else {
-                "None"
-            }
-        )?;
-        writeln!(&mut self.buf, "            None,")?;
-        writeln!(&mut self.buf, "            None,")?;
-        writeln!(&mut self.buf, "        )")?;
-        writeln!(&mut self.buf, "        .await?;")?;
-        writeln!(
-            &mut self.buf,
-            "        serde_json::from_slice(&body).map_err(|e| e.into())"
-        )?;
-        writeln!(&mut self.buf, "    }}")?;
-        writeln!(&mut self.buf, "}}")?;
-        // parameters
-        if let Some(LexXrpcQueryParameter::Params(parameters)) = &query.parameters {
-            let required = if let Some(required) = &parameters.required {
-                HashSet::from_iter(required)
-            } else {
-                HashSet::new()
-            };
-
-            writeln!(&mut self.buf)?;
-            writeln!(
-                &mut self.buf,
-                "#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]"
-            )?;
-            writeln!(&mut self.buf, r#"#[serde(rename_all = "camelCase")]"#)?;
-            writeln!(&mut self.buf, "pub struct Parameters {{")?;
-            for key in parameters.properties.keys().sorted() {
-                let property = match &parameters.properties[key] {
-                    LexXrpcParametersProperty::Boolean(boolean) => {
-                        LexObjectProperty::Boolean(boolean.clone())
-                    }
-                    LexXrpcParametersProperty::Integer(integer) => {
-                        LexObjectProperty::Integer(integer.clone())
-                    }
-                    LexXrpcParametersProperty::String(string) => {
-                        LexObjectProperty::String(string.clone())
-                    }
-                    LexXrpcParametersProperty::Unknown(unknown) => {
-                        LexObjectProperty::Unknown(unknown.clone())
-                    }
-                    LexXrpcParametersProperty::Array(primitive_array) => {
-                        let items = match &primitive_array.items {
-                            LexPrimitiveArrayItem::Boolean(b) => LexArrayItem::Boolean(b.clone()),
-                            LexPrimitiveArrayItem::Integer(i) => LexArrayItem::Integer(i.clone()),
-                            LexPrimitiveArrayItem::String(s) => LexArrayItem::String(s.clone()),
-                            LexPrimitiveArrayItem::Unknown(u) => LexArrayItem::Unknown(u.clone()),
-                        };
-                        LexObjectProperty::Array(LexArray {
-                            description: primitive_array.description.clone(),
-                            items,
-                            min_length: primitive_array.min_length,
-                            max_length: primitive_array.max_length,
-                        })
-                    }
-                };
-                self.write_object_property(key, &property, required.contains(key), "Parameters")?;
-            }
-            writeln!(&mut self.buf, "}}")?;
-        }
-        // output
-        if let Some(output) = &query.output {
-            writeln!(&mut self.buf)?;
-            if let Some(description) = &output.description {
-                writeln!(&mut self.buf, "/// {description}")?;
-            }
-            if let Some(schema) = &output.schema {
-                match schema {
-                    LexXrpcBodySchema::Ref(r#ref) => {
-                        if let Some(description) = &r#ref.description {
-                            writeln!(&mut self.buf, "/// {description}")?;
-                        }
-                        writeln!(
-                            &mut self.buf,
-                            "pub type Output = {};",
-                            Self::ref_type(r#ref)
-                        )?;
-                    }
-                    LexXrpcBodySchema::Union(_) => unimplemented!(),
-                    LexXrpcBodySchema::Object(object) => {
-                        self.write_object("Output", object)?;
-                    }
-                }
-            }
-        }
-        // error
-        self.write_xrpc_errors(&query.errors)?;
-        Ok(())
-    }
-    fn write_procedure(
-        &mut self,
-        schema_id: &str,
-        name: &str,
-        procedure: &LexXrpcProcedure,
-    ) -> Result<()> {
-        if let Some(description) = &procedure.description {
-            writeln!(&mut self.buf, "/// {}", description)?;
-        }
-        let has_input = procedure
-            .input
-            .as_ref()
-            .map_or(false, |i| i.schema.is_some());
-        let has_output = procedure
-            .output
-            .as_ref()
-            .map_or(false, |o| o.schema.is_some());
-        writeln!(&mut self.buf, "#[async_trait::async_trait]")?;
-        writeln!(
-            &mut self.buf,
-            "pub trait {}: crate::xrpc::XrpcClient {{",
-            name.to_pascal_case()
-        )?;
-        writeln!(
-            &mut self.buf,
-            "    async fn {}(&self, input: {}) -> Result<{}, Box<dyn std::error::Error>> {{",
-            name.to_snake_case(),
-            if has_input { "Input" } else { "Vec<u8>" },
-            if has_output { "Output" } else { "()" }
-        )?;
-        writeln!(
-            &mut self.buf,
-            "        let {} = crate::xrpc::XrpcClient::send::<Error>(",
-            if has_output { "body" } else { "_" }
-        )?;
-        writeln!(&mut self.buf, "            self,")?;
-        writeln!(&mut self.buf, "            http::Method::POST,")?;
-        writeln!(&mut self.buf, "            {schema_id:?},")?;
-        writeln!(&mut self.buf, "            None,")?;
-        writeln!(
-            &mut self.buf,
-            "            Some({}),",
-            if has_input {
-                "serde_json::to_vec(&input)?"
-            } else {
-                "input"
-            }
-        )?;
-        writeln!(
-            &mut self.buf,
-            "            {},",
-            if let Some(input) = &procedure.input {
-                format!("Some(String::from({:?}))", input.encoding)
-            } else {
-                String::from("None")
-            }
-        )?;
-        writeln!(&mut self.buf, "        )")?;
-        writeln!(&mut self.buf, "        .await?;")?;
-        writeln!(
-            &mut self.buf,
-            "        {}",
-            if has_output {
-                "serde_json::from_slice(&body).map_err(|e| e.into())"
-            } else {
-                "Ok(())"
-            }
-        )?;
-        writeln!(&mut self.buf, "    }}")?;
-        writeln!(&mut self.buf, "}}")?;
-        if procedure.parameters.is_some() {
-            // TODO
-        }
-        // input
-        if let Some(input) = &procedure.input {
-            writeln!(&mut self.buf)?;
-            if let Some(description) = &input.description {
-                writeln!(&mut self.buf, "/// {description}")?;
-            }
-            if let Some(schema) = &input.schema {
-                match schema {
-                    LexXrpcBodySchema::Ref(_) => unimplemented!(),
-                    LexXrpcBodySchema::Union(_) => unimplemented!(),
-                    LexXrpcBodySchema::Object(object) => {
-                        self.write_object("Input", object)?;
-                    }
-                }
-            }
-        }
-        // output
-        if let Some(output) = &procedure.output {
-            writeln!(&mut self.buf)?;
-            if let Some(description) = &output.description {
-                writeln!(&mut self.buf, "/// {description}")?;
-            }
-            if let Some(schema) = &output.schema {
-                match schema {
-                    LexXrpcBodySchema::Ref(r#ref) => {
-                        if let Some(description) = &r#ref.description {
-                            writeln!(&mut self.buf, "/// {description}")?;
-                        }
-                        writeln!(
-                            &mut self.buf,
-                            "pub type Output = {};",
-                            Self::ref_type(r#ref)
-                        )?;
-                    }
-                    LexXrpcBodySchema::Union(_) => unimplemented!(),
-                    LexXrpcBodySchema::Object(object) => {
-                        self.write_object("Output", object)?;
-                    }
-                }
-            }
-        }
-        // error
-        self.write_xrpc_errors(&procedure.errors)?;
-        Ok(())
-    }
-    fn write_xrpc_errors(&mut self, errors: &Option<Vec<LexXrpcError>>) -> Result<()> {
-        writeln!(&mut self.buf)?;
-        writeln!(
-            &mut self.buf,
-            "#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]"
-        )?;
-        writeln!(
-            &mut self.buf,
-            r#"#[serde(tag = "error", content = "message")]"#
-        )?;
-        writeln!(&mut self.buf, "pub enum Error {{")?;
-        if let Some(errors) = errors {
-            for error in errors {
-                if let Some(description) = &error.description {
-                    writeln!(&mut self.buf, "    /// {}", description)?;
-                }
-                writeln!(
-                    &mut self.buf,
-                    "    {}(Option<String>),",
-                    error.name.to_pascal_case()
-                )?;
-            }
-        }
-        writeln!(&mut self.buf, "}}")?;
-        Ok(())
-    }
-    fn write_subscription(&mut self, _: &str, _: &LexXrpcSubscription) -> Result<()> {
-        // TODO
-        writeln!(&mut self.buf, "// TODO")?;
-        Ok(())
-    }
-    fn write_token(&mut self, name: &str, token: &LexToken) -> Result<()> {
-        if let Some(description) = &token.description {
-            writeln!(&mut self.buf, "/// {}", description)?;
-        }
-        // TODO: enum?
-        writeln!(&mut self.buf, "pub struct {};", name.to_pascal_case())?;
-        Ok(())
-    }
-    fn write_object(&mut self, name: &str, object: &LexObject) -> Result<()> {
-        if let Some(description) = &object.description {
-            writeln!(&mut self.buf, "/// {}", description)?;
-        }
-        let required = if let Some(required) = &object.required {
-            HashSet::from_iter(required)
-        } else {
-            HashSet::new()
-        };
-        writeln!(
-            &mut self.buf,
-            "#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]"
-        )?;
-        writeln!(&mut self.buf, r#"#[serde(rename_all = "camelCase")]"#)?;
-        writeln!(&mut self.buf, "pub struct {} {{", name.to_pascal_case())?;
-        if let Some(properties) = &object.properties {
-            for key in properties.keys().sorted() {
-                self.write_object_property(key, &properties[key], required.contains(key), name)?;
-            }
-        }
-        writeln!(&mut self.buf, "}}")?;
-        Ok(())
-    }
-    fn write_object_property(
-        &mut self,
-        name: &str,
-        property: &LexObjectProperty,
-        required: bool,
-        object_name: &str,
-    ) -> Result<()> {
-        match property {
-            LexObjectProperty::Ref(r#ref) => {
-                if let Some(description) = &r#ref.description {
-                    writeln!(&mut self.buf, "    /// {}", description)?;
-                }
-                let ref_type = Self::ref_type(r#ref);
-                let field_type = if required {
-                    ref_type
-                } else {
-                    writeln!(
-                        &mut self.buf,
-                        r#"    #[serde(skip_serializing_if = "Option::is_none")]"#
-                    )?;
-                    format!("Option<{ref_type}>")
-                };
-                writeln!(
-                    &mut self.buf,
-                    "    pub {}: {field_type},",
-                    name.to_snake_case()
-                )?;
-            }
-            LexObjectProperty::Union(union) => {
-                if let Some(description) = &union.description {
-                    writeln!(&mut self.buf, "    /// {}", description)?;
-                }
-                // Use `Box` to avoid recursive.
-                let ref_type = format!("Box<{object_name}{}Enum>", name.to_pascal_case());
-                let field_type = if required {
-                    ref_type
-                } else {
-                    writeln!(
-                        &mut self.buf,
-                        r#"    #[serde(skip_serializing_if = "Option::is_none")]"#
-                    )?;
-                    format!("Option<{ref_type}>")
-                };
-                writeln!(
-                    &mut self.buf,
-                    "    pub {}: {field_type},",
-                    name.to_snake_case()
-                )?;
-            }
-            LexObjectProperty::Bytes(bytes) => {
-                if let Some(description) = &bytes.description {
-                    writeln!(&mut self.buf, "    /// {}", description)?;
-                }
-                // TODO
-                writeln!(&mut self.buf, "    // pub {}: ...,", name.to_snake_case())?;
-            }
-            LexObjectProperty::CidLink(cid_link) => {
-                if let Some(description) = &cid_link.description {
-                    writeln!(&mut self.buf, "    /// {}", description)?;
-                }
-                // TODO
-                writeln!(&mut self.buf, "    // pub {}: ...,", name.to_snake_case())?;
-            }
-            LexObjectProperty::Array(array) => {
-                if let Some(description) = &array.description {
-                    writeln!(&mut self.buf, "    /// {}", description)?;
-                }
-                let item_type = match &array.items {
-                    LexArrayItem::Boolean(_) => String::from("bool"),
-                    LexArrayItem::Integer(_) => String::from("i32"),
-                    LexArrayItem::String(_) => String::from("String"),
-                    LexArrayItem::Unknown(_) => String::from(""), // TODO
-                    LexArrayItem::Bytes(_) => String::from(""),   // TODO
-                    LexArrayItem::CidLink(_) => String::from(""), // TODO
-                    LexArrayItem::Blob(_) => String::from("crate::blob::BlobRef"), // TODO
-                    LexArrayItem::Ref(r#ref) => Self::ref_type(r#ref),
-                    LexArrayItem::Union(_) => format!("{object_name}{}Item", name.to_pascal_case()), // TODO
-                };
-                let field_type = if required {
-                    format!("Vec<{}>", item_type)
-                } else {
-                    format!("Option<Vec<{}>>", item_type)
-                };
-                if item_type.is_empty() {
-                    writeln!(
-                        &mut self.buf,
-                        "    // pub {}: Vec<...>",
-                        name.to_snake_case()
-                    )?;
-                } else {
-                    if !required {
-                        writeln!(
-                            &mut self.buf,
-                            r#"    #[serde(skip_serializing_if = "Option::is_none")]"#
-                        )?;
-                    }
-                    writeln!(
-                        &mut self.buf,
-                        "    pub {}: {field_type},",
-                        name.to_snake_case()
-                    )?;
-                }
-            }
-            LexObjectProperty::Blob(blob) => {
-                if let Some(description) = &blob.description {
-                    writeln!(&mut self.buf, "    /// {}", description)?;
-                }
-                let field_type = if required {
-                    "crate::blob::BlobRef"
-                } else {
-                    writeln!(
-                        &mut self.buf,
-                        r#"    #[serde(skip_serializing_if = "Option::is_none")]"#
-                    )?;
-                    "Option<crate::blob::BlobRef>"
-                };
-                writeln!(
-                    &mut self.buf,
-                    "    pub {}: {field_type},",
-                    name.to_snake_case()
-                )?;
-            }
-            LexObjectProperty::Boolean(boolean) => {
-                if let Some(description) = &boolean.description {
-                    writeln!(&mut self.buf, "    /// {}", description)?;
-                }
-                let field_type = if required {
-                    "bool"
-                } else {
-                    writeln!(
-                        &mut self.buf,
-                        r#"    #[serde(skip_serializing_if = "Option::is_none")]"#
-                    )?;
-                    "Option<bool>"
-                };
-                writeln!(
-                    &mut self.buf,
-                    "    pub {}: {field_type},",
-                    name.to_snake_case()
-                )?;
-            }
-            LexObjectProperty::Integer(integer) => {
-                if let Some(description) = &integer.description {
-                    writeln!(&mut self.buf, "    /// {}", description)?;
-                }
-                // TODO: usize?
-                let field_type = if required {
-                    "i32"
-                } else {
-                    writeln!(
-                        &mut self.buf,
-                        r#"    #[serde(skip_serializing_if = "Option::is_none")]"#
-                    )?;
-                    "Option<i32>"
-                };
-                writeln!(
-                    &mut self.buf,
-                    "    pub {}: {field_type},",
-                    name.to_snake_case()
-                )?;
-            }
-            LexObjectProperty::String(string) => {
-                if let Some(description) = &string.description {
-                    writeln!(&mut self.buf, "    /// {}", description)?;
-                }
-                // TODO: enum?
-                let field_type = if required {
-                    "String"
-                } else {
-                    writeln!(
-                        &mut self.buf,
-                        r#"    #[serde(skip_serializing_if = "Option::is_none")]"#
-                    )?;
-                    "Option<String>"
-                };
-                writeln!(
-                    &mut self.buf,
-                    "    pub {}: {field_type},",
-                    // TODO: other keywords?
-                    if name == "type" {
-                        String::from("r#type")
-                    } else {
-                        name.to_snake_case()
-                    }
-                )?;
-            }
-            // = Record enum
-            LexObjectProperty::Unknown(unknown) => {
-                if let Some(description) = &unknown.description {
-                    writeln!(&mut self.buf, "    /// {}", description)?;
-                }
-                writeln!(
-                    &mut self.buf,
-                    "    pub {}: crate::records::Record,",
-                    name.to_snake_case()
-                )?;
-            }
-        }
-        Ok(())
-    }
-    fn write_string(&mut self, name: &str, string: &atrium_lex::lexicon::LexString) -> Result<()> {
-        if let Some(description) = &string.description {
-            writeln!(&mut self.buf, "/// {}", description)?;
-        }
-        // TODO: enum?
-        writeln!(
-            &mut self.buf,
-            "#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]"
-        )?;
-        writeln!(&mut self.buf, "pub struct {};", name.to_pascal_case())?;
-        Ok(())
-    }
-
-    fn ref_type(r#ref: &LexRef) -> String {
-        let (namespace, def) = r#ref
-            .r#ref
-            .split_once('#')
-            .unwrap_or((&r#ref.r#ref, "main"));
-        if namespace.is_empty() {
-            def.to_pascal_case()
-        } else {
-            format!(
-                "crate::{}::{}",
-                namespace.split('.').map(str::to_snake_case).join("::"),
-                def.to_pascal_case()
-            )
-        }
-    }
-}
diff --git a/atrium-codegen/src/fs.rs b/atrium-codegen/src/fs.rs
index 86629d98..278297aa 100644
--- a/atrium-codegen/src/fs.rs
+++ b/atrium-codegen/src/fs.rs
@@ -18,7 +18,7 @@ where
     Ok(())
 }
 
-pub(crate) fn find_schemas(path: &Path) -> Result<Vec<PathBuf>> {
+pub(crate) fn find_schemas(path: &Path) -> Result<Vec<impl AsRef<Path>>> {
     let mut results = Vec::new();
     walk(path, &mut results, &mut |path| {
         path.extension().and_then(OsStr::to_str) == Some("json")
@@ -26,7 +26,7 @@ pub(crate) fn find_schemas(path: &Path) -> Result<Vec<PathBuf>> {
     Ok(results)
 }
 
-pub(crate) fn find_dirs(path: &Path) -> Result<Vec<PathBuf>> {
+pub(crate) fn find_dirs(path: &Path) -> Result<Vec<impl AsRef<Path>>> {
     let mut results = Vec::new();
     walk(path, &mut results, &mut |path| path.is_dir())?;
     Ok(results)
diff --git a/atrium-codegen/src/generator.rs b/atrium-codegen/src/generator.rs
index b0a49109..6699e70f 100644
--- a/atrium-codegen/src/generator.rs
+++ b/atrium-codegen/src/generator.rs
@@ -1,48 +1,75 @@
-use crate::code_writer::CodeWriter;
 use crate::fs::find_dirs;
 use crate::schema::find_ref_unions;
+use crate::token_stream::{modules, refs_enum, traits_macro, LexConverter};
 use atrium_lex::lexicon::LexUserType;
 use atrium_lex::LexiconDoc;
 use heck::ToSnakeCase;
 use itertools::Itertools;
-use std::fs::{create_dir_all, read_dir};
-use std::io::Result;
+use proc_macro2::TokenStream;
+use quote::quote;
+use std::error::Error;
+use std::fs::{create_dir_all, read_dir, File};
+use std::io::Write;
 use std::path::{Path, PathBuf};
 
-pub(crate) fn generate_code(schema: &LexiconDoc, outdir: &Path) -> Result<()> {
+const HEADER: &str = "// This file is generated by atrium-codegen. DO NOT EDIT.";
+
+pub(crate) fn generate_schemas(
+    schema: &LexiconDoc,
+    outdir: &Path,
+) -> Result<Vec<PathBuf>, Box<dyn Error>> {
+    let mut results = Vec::new();
     let mut paths = schema.id.split('.').collect::<Vec<_>>();
     if let Some(basename) = paths.pop() {
-        create_dir_all(outdir.join(paths.join("/")))?;
-        let mut writer = CodeWriter::default();
-        writer.write_header(schema.description.as_ref(), Some(&schema.id))?;
+        let mut tokens = Vec::new();
         let mut names = Vec::new();
+        let converter = LexConverter::new(schema.id.clone());
+        // main def
         for (name, def) in &schema.defs {
             if name == "main" {
-                writer.write_user_type(&schema.id, basename, def, true)?;
+                tokens.push(converter.convert(basename, def, true)?);
             } else {
                 names.push(name);
             }
         }
+        // other defs
         for &name in names.iter().sorted() {
-            let def = &schema.defs[name];
-            assert!(!matches!(
-                def,
-                LexUserType::Record(_)
-                    | LexUserType::XrpcProcedure(_)
-                    | LexUserType::XrpcQuery(_)
-                    | LexUserType::XrpcSubscription(_)
-            ));
-            writer.write_user_type(&schema.id, name, def, false)?;
+            tokens.push(converter.convert(name, &schema.defs[name], false)?);
         }
-        writer.write_ref_unions(&schema.id, &find_ref_unions(&schema.defs))?;
+        // ref unions
+        tokens.push(converter.ref_unions(&find_ref_unions(&schema.defs))?);
+
+        let documentation = {
+            let doc = format!("Definitions for the `{}` namespace.", schema.id);
+            let description = if let Some(description) = &schema.description {
+                quote!(#![doc = #description])
+            } else {
+                quote!()
+            };
+            quote! {
+                #![doc = #doc]
+                #description
+            }
+        };
+        let content = quote! {
+            #documentation
+            #(#tokens)*
+        };
+        let dir = outdir.join(paths.join("/"));
+        create_dir_all(&dir)?;
         let mut filename = PathBuf::from(basename.to_snake_case());
         filename.set_extension("rs");
-        writer.write_to_file(&outdir.join(paths.join("/")).join(filename))?;
+        let path = dir.join(filename);
+        write_to_file(File::create(&path)?, content)?;
+        results.push(path);
     }
-    Ok(())
+    Ok(results)
 }
 
-pub(crate) fn generate_records(outdir: &Path, schemas: &[LexiconDoc]) -> Result<()> {
+pub(crate) fn generate_records(
+    outdir: &Path,
+    schemas: &[LexiconDoc],
+) -> Result<PathBuf, Box<dyn Error>> {
     let records = schemas
         .iter()
         .filter_map(|schema| {
@@ -54,14 +81,20 @@ pub(crate) fn generate_records(outdir: &Path, schemas: &[LexiconDoc]) -> Result<
         })
         .sorted()
         .collect_vec();
-    let mut writer = CodeWriter::default();
-    writer.write_header(None, None)?;
-    writer.write_records(&records)?;
-    writer.write_to_file(&outdir.join("records.rs"))?;
-    Ok(())
+    let tokens = refs_enum("Record", &records, None)?;
+    let content = quote! {
+        #![doc = "A collection of ATP repository record types."]
+        #tokens
+    };
+    let path = outdir.join("records.rs");
+    write_to_file(File::create(&path)?, content)?;
+    Ok(path)
 }
 
-pub(crate) fn generate_traits(outdir: &Path, schemas: &[LexiconDoc]) -> Result<()> {
+pub(crate) fn generate_traits(
+    outdir: &Path,
+    schemas: &[LexiconDoc],
+) -> Result<PathBuf, Box<dyn Error>> {
     let traits = schemas
         .iter()
         .filter_map(|schema| {
@@ -75,28 +108,32 @@ pub(crate) fn generate_traits(outdir: &Path, schemas: &[LexiconDoc]) -> Result<(
         })
         .sorted()
         .collect_vec();
-    let mut writer = CodeWriter::default();
-    writer.write_header(None, None)?;
-    writer.write_traits_macro(&traits)?;
-    writer.write_to_file(&outdir.join("traits.rs"))?;
-    Ok(())
+    let tokens = traits_macro(&traits)?;
+    let content = quote! {
+        #![doc = "A macro for implementing the traits of all XRPC requests."]
+        #tokens
+    };
+    let path = outdir.join("traits.rs");
+    write_to_file(File::create(&path)?, content)?;
+    Ok(path)
 }
 
-pub(crate) fn generate_modules(outdir: &Path) -> Result<()> {
+pub(crate) fn generate_modules(outdir: &Path) -> Result<Vec<PathBuf>, Box<dyn Error>> {
     let paths = find_dirs(outdir)?;
     let mut files = Vec::with_capacity(paths.len());
-    // create ".rs" files
+    // generate ".rs" files names
     for path in &paths {
-        let mut p = path.to_path_buf();
-        p.set_extension("rs");
-        files.push(p);
+        if path.as_ref() == outdir {
+            files.push(outdir.join("lib.rs"));
+        } else {
+            let mut p = path.as_ref().to_path_buf();
+            p.set_extension("rs");
+            files.push(p);
+        }
     }
     // write "mod" statements
     for (path, filepath) in paths.iter().zip(&files) {
-        if path == outdir {
-            continue;
-        }
-        let modules = read_dir(path)?
+        let names = read_dir(path)?
             .filter_map(Result::ok)
             .filter(|entry| entry.path().is_file())
             .filter_map(|entry| {
@@ -107,11 +144,23 @@ pub(crate) fn generate_modules(outdir: &Path) -> Result<()> {
             })
             .sorted()
             .collect_vec();
-
-        let mut writer = CodeWriter::default();
-        writer.write_header(None, None)?;
-        writer.write_mods(&modules)?;
-        writer.write_to_file(filepath)?;
+        let tokens = modules(&names)?;
+        let documentation = if path.as_ref() == outdir {
+            quote!(#![doc = include_str!("../README.md")])
+        } else {
+            quote!()
+        };
+        let content = quote! {
+            #documentation
+            #tokens
+        };
+        write_to_file(File::create(filepath)?, content)?;
     }
+    Ok(files)
+}
+
+fn write_to_file(mut file: impl Write, content: TokenStream) -> Result<(), std::io::Error> {
+    writeln!(file, "{HEADER}")?;
+    writeln!(file, "{content}")?;
     Ok(())
 }
diff --git a/atrium-codegen/src/lib.rs b/atrium-codegen/src/lib.rs
index 8dc79b1d..b3469140 100644
--- a/atrium-codegen/src/lib.rs
+++ b/atrium-codegen/src/lib.rs
@@ -1,16 +1,21 @@
-mod code_writer;
 mod fs;
 mod generator;
 mod schema;
+mod token_stream;
 
-use crate::generator::{generate_code, generate_modules, generate_records, generate_traits};
+use crate::generator::{generate_modules, generate_records, generate_schemas, generate_traits};
 use atrium_lex::LexiconDoc;
+use itertools::Itertools;
 use serde_json::from_reader;
+use std::error::Error;
 use std::fs::File;
-use std::io::Result;
-use std::path::Path;
+use std::path::{Path, PathBuf};
 
-pub fn genapi(lexdir: impl AsRef<Path>, outdir: impl AsRef<Path>, prefix: &str) -> Result<()> {
+pub fn genapi(
+    lexdir: impl AsRef<Path>,
+    outdir: impl AsRef<Path>,
+    prefixes: &[&str],
+) -> Result<Vec<impl AsRef<Path>>, Box<dyn Error>> {
     let lexdir = lexdir.as_ref().canonicalize()?;
     let outdir = outdir.as_ref().canonicalize()?;
     let paths = fs::find_schemas(&lexdir)?;
@@ -18,14 +23,24 @@ pub fn genapi(lexdir: impl AsRef<Path>, outdir: impl AsRef<Path>, prefix: &str)
     for path in &paths {
         schemas.push(from_reader::<_, LexiconDoc>(File::open(path)?)?);
     }
-    for schema in schemas
-        .iter()
-        .filter(|schema| schema.id.starts_with(prefix))
-    {
-        generate_code(schema, &outdir)?;
+    let mut results = Vec::new();
+    for &prefix in prefixes {
+        let targets = schemas
+            .iter()
+            .filter(|schema| schema.id.starts_with(prefix))
+            .collect_vec();
+        results.extend(self::gen(&outdir, &targets)?);
     }
-    generate_records(&outdir, &schemas)?;
-    generate_traits(&outdir, &schemas)?;
-    generate_modules(&outdir)?;
-    Ok(())
+    results.push(generate_records(&outdir, &schemas)?);
+    results.push(generate_traits(&outdir, &schemas)?);
+    results.extend(generate_modules(&outdir)?);
+    Ok(results)
+}
+
+fn gen(outdir: &Path, schemas: &[&LexiconDoc]) -> Result<Vec<PathBuf>, Box<dyn Error>> {
+    let mut results = Vec::new();
+    for &schema in schemas {
+        results.extend(generate_schemas(schema, outdir)?);
+    }
+    Ok(results)
 }
diff --git a/atrium-codegen/src/token_stream.rs b/atrium-codegen/src/token_stream.rs
new file mode 100644
index 00000000..706b5d07
--- /dev/null
+++ b/atrium-codegen/src/token_stream.rs
@@ -0,0 +1,609 @@
+use atrium_lex::lexicon::*;
+use heck::{ToPascalCase, ToSnakeCase};
+use itertools::Itertools;
+use proc_macro2::TokenStream;
+use quote::{format_ident, quote};
+use std::collections::HashSet;
+use syn::{Path, Result};
+
+pub(crate) struct LexConverter {
+    schema_id: String,
+}
+
+impl LexConverter {
+    pub fn new(schema_id: String) -> Self {
+        Self { schema_id }
+    }
+    pub fn convert(&self, name: &str, def: &LexUserType, is_main: bool) -> Result<TokenStream> {
+        let def_name = if is_main {
+            String::new()
+        } else {
+            format!("#{name}")
+        };
+        let description = format!("`{}{}`", self.schema_id, def_name);
+        let user_type = match def {
+            LexUserType::Record(record) => self.record(record)?,
+            LexUserType::XrpcQuery(query) => self.query(name, query)?,
+            LexUserType::XrpcProcedure(procedure) => self.procedure(name, procedure)?,
+            LexUserType::XrpcSubscription(subscription) => self.subscription(name, subscription)?,
+            LexUserType::Token(token) => self.token(name, token)?,
+            LexUserType::Object(object) => {
+                self.object(if is_main { "Main" } else { name }, object)?
+            }
+            LexUserType::String(string) => self.string(name, string)?,
+            _ => unimplemented!("{def:?}"),
+        };
+        Ok(quote! {
+            #[doc = #description]
+            #user_type
+        })
+    }
+    pub fn ref_unions(&self, ref_unions: &[(String, LexRefUnion)]) -> Result<TokenStream> {
+        let mut enums = Vec::new();
+        for (name, ref_union) in ref_unions {
+            enums.push(self::refs_enum(
+                name,
+                &ref_union.refs,
+                Some(&self.schema_id),
+            )?);
+        }
+        Ok(quote!(#(#enums)*))
+    }
+    fn record(&self, record: &LexRecord) -> Result<TokenStream> {
+        let LexRecordRecord::Object(object) = &record.record;
+        self.object("Record", object)
+    }
+    fn xrpc_parameters(&self, parameters: &LexXrpcParameters) -> Result<TokenStream> {
+        let properties = parameters
+            .properties
+            .iter()
+            .map(|(k, v)| {
+                let value = match v {
+                    LexXrpcParametersProperty::Boolean(boolean) => {
+                        LexObjectProperty::Boolean(boolean.clone())
+                    }
+                    LexXrpcParametersProperty::Integer(integer) => {
+                        LexObjectProperty::Integer(integer.clone())
+                    }
+                    LexXrpcParametersProperty::String(string) => {
+                        LexObjectProperty::String(string.clone())
+                    }
+                    LexXrpcParametersProperty::Unknown(unknown) => {
+                        LexObjectProperty::Unknown(unknown.clone())
+                    }
+                    LexXrpcParametersProperty::Array(primitive_array) => {
+                        LexObjectProperty::Array(LexArray {
+                            description: primitive_array.description.clone(),
+                            items: match &primitive_array.items {
+                                LexPrimitiveArrayItem::Boolean(b) => {
+                                    LexArrayItem::Boolean(b.clone())
+                                }
+                                LexPrimitiveArrayItem::Integer(i) => {
+                                    LexArrayItem::Integer(i.clone())
+                                }
+                                LexPrimitiveArrayItem::String(s) => LexArrayItem::String(s.clone()),
+                                LexPrimitiveArrayItem::Unknown(u) => {
+                                    LexArrayItem::Unknown(u.clone())
+                                }
+                            },
+                            min_length: primitive_array.min_length,
+                            max_length: primitive_array.max_length,
+                        })
+                    }
+                };
+                (k.clone(), value)
+            })
+            .collect();
+        self.object(
+            "Parameters",
+            &LexObject {
+                description: parameters.description.clone(),
+                required: parameters.required.clone(),
+                nullable: None,
+                properties: Some(properties),
+            },
+        )
+    }
+    fn xrpc_body(&self, name: &str, body: &LexXrpcBody) -> Result<TokenStream> {
+        let description = self.description(&body.description);
+        let schema = if let Some(schema) = &body.schema {
+            match schema {
+                LexXrpcBodySchema::Ref(r#ref) => {
+                    let type_name = format_ident!("{}", name.to_pascal_case());
+                    let (description, ref_type) = self.ref_type(r#ref)?;
+                    quote! {
+                        #description
+                        pub type #type_name = #ref_type;
+                    }
+                }
+                LexXrpcBodySchema::Object(object) => self.object(name, object)?,
+                _ => unimplemented!("{schema:?}"),
+            }
+        } else {
+            return Ok(quote!());
+        };
+        Ok(quote! {
+            #description
+            #schema
+        })
+    }
+    fn xrpc_errors(&self, errors: &Option<Vec<LexXrpcError>>) -> Result<TokenStream> {
+        let derives = self::derives()?;
+        let variants = errors.as_ref().map_or(Vec::new(), |e| {
+            e.iter()
+                .map(|error| {
+                    let description = self.description(&error.description);
+                    let name = format_ident!("{}", error.name.to_pascal_case());
+                    quote! {
+                        #description
+                        #name(Option<String>)
+                    }
+                })
+                .collect()
+        });
+        Ok(quote! {
+            #derives
+            #[serde(tag = "error", content = "message")]
+            pub enum Error {
+                #(#variants),*
+            }
+        })
+    }
+    fn query(&self, name: &str, query: &LexXrpcQuery) -> Result<TokenStream> {
+        let description = self.description(&query.description);
+        let parameters = &query.parameters;
+        let output = query.output.as_ref();
+        let trait_impl: TokenStream = self.xrpc_trait_query(
+            name,
+            parameters.is_some(),
+            output.map_or(false, |o| o.schema.is_some()),
+        )?;
+        let params = if let Some(LexXrpcQueryParameter::Params(parameters)) = parameters {
+            self.xrpc_parameters(parameters)?
+        } else {
+            quote!()
+        };
+        let outputs = if let Some(body) = output {
+            self.xrpc_body("Output", body)?
+        } else {
+            quote!()
+        };
+        let errors = self.xrpc_errors(&query.errors)?;
+        Ok(quote! {
+            #description
+            #trait_impl
+            #params
+            #outputs
+            #errors
+        })
+    }
+    fn procedure(&self, name: &str, procedure: &LexXrpcProcedure) -> Result<TokenStream> {
+        let description = self.description(&procedure.description);
+        let input = procedure.input.as_ref();
+        let output = procedure.output.as_ref();
+        let trait_impl: TokenStream =
+            self.xrpc_trait_procedure(name, input, output.map_or(false, |o| o.schema.is_some()))?;
+        let inputs = if let Some(body) = input {
+            self.xrpc_body("Input", body)?
+        } else {
+            quote!()
+        };
+        let outputs = if let Some(body) = output {
+            self.xrpc_body("Output", body)?
+        } else {
+            quote!()
+        };
+        let errors = self.xrpc_errors(&procedure.errors)?;
+        Ok(quote! {
+            #description
+            #trait_impl
+            #inputs
+            #outputs
+            #errors
+        })
+    }
+    fn xrpc_trait_query(
+        &self,
+        name: &str,
+        has_params: bool,
+        has_output: bool,
+    ) -> Result<TokenStream> {
+        let mut args = vec![quote!(&self)];
+        if has_params {
+            args.push(quote!(params: Parameters));
+        }
+        let param_value = if has_params {
+            quote!(Some(serde_urlencoded::to_string(&params)?))
+        } else {
+            quote!(None)
+        };
+        let nsid = &self.schema_id;
+        let xrpc_call = quote! {
+            crate::xrpc::XrpcClient::send::<Error>(
+                self,
+                http::Method::GET,
+                #nsid,
+                #param_value,
+                None,
+                None,
+            )
+            .await?
+        };
+        self.xrpc_trait_common(name, &xrpc_call, &args, has_output)
+    }
+    fn xrpc_trait_procedure(
+        &self,
+        name: &str,
+        input: Option<&LexXrpcBody>,
+        has_output: bool,
+    ) -> Result<TokenStream> {
+        let mut args = vec![quote!(&self)];
+        if let Some(body) = &input {
+            if body.schema.is_some() {
+                args.push(quote!(input: Input));
+            } else {
+                args.push(quote!(input: Vec<u8>));
+            }
+        }
+        let (input_value, encoding) = if let Some(body) = &input {
+            let encoding = &body.encoding;
+            if body.schema.is_some() {
+                (
+                    quote!(Some(serde_json::to_vec(&input)?)),
+                    quote!(Some(String::from(#encoding))),
+                )
+            } else {
+                (quote!(Some(input)), quote!(Some(String::from(#encoding))))
+            }
+        } else {
+            (quote!(None), quote!(None))
+        };
+        let nsid = &self.schema_id;
+        let xrpc_call = quote! {
+            crate::xrpc::XrpcClient::send::<Error>(
+                self,
+                http::Method::POST,
+                #nsid,
+                None,
+                #input_value,
+                #encoding,
+            )
+            .await?
+        };
+        self.xrpc_trait_common(name, &xrpc_call, &args, has_output)
+    }
+    fn xrpc_trait_common(
+        &self,
+        name: &str,
+        xrpc_call: &TokenStream,
+        args: &[TokenStream],
+        has_output: bool,
+    ) -> Result<TokenStream> {
+        let trait_name = format_ident!("{}", name.to_pascal_case());
+        let method_name = format_ident!("{}", name.to_snake_case());
+        let body = if has_output {
+            quote! {
+                async fn #method_name(#(#args),*) -> Result<Output, Box<dyn std::error::Error>> {
+                    let body = #xrpc_call;
+                    serde_json::from_slice(&body).map_err(|e| e.into())
+                }
+            }
+        } else {
+            quote! {
+                async fn #method_name(#(#args),*) -> Result<(), Box<dyn std::error::Error>> {
+                    let _ = #xrpc_call;
+                    Ok(())
+                }
+            }
+        };
+        Ok(quote! {
+            #[async_trait::async_trait]
+            pub trait #trait_name: crate::xrpc::XrpcClient {
+                #body
+            }
+        })
+    }
+    fn subscription(&self, name: &str, subscription: &LexXrpcSubscription) -> Result<TokenStream> {
+        let description = self.description(&subscription.description);
+        let subscription_name = format_ident!("{}", name.to_pascal_case());
+        // TODO
+        Ok(quote! {
+            #description
+            pub struct #subscription_name;
+        })
+    }
+    fn token(&self, name: &str, token: &LexToken) -> Result<TokenStream> {
+        let description = self.description(&token.description);
+        let token_name = format_ident!("{}", name.to_pascal_case());
+        // TODO
+        Ok(quote! {
+            #description
+            pub struct #token_name;
+        })
+    }
+    fn object(&self, name: &str, object: &LexObject) -> Result<TokenStream> {
+        let description = self.description(&object.description);
+        let derives = self::derives()?;
+        let struct_name = format_ident!("{}", name.to_pascal_case());
+        let required = if let Some(required) = &object.required {
+            HashSet::from_iter(required)
+        } else {
+            HashSet::new()
+        };
+        let mut fields = Vec::new();
+        if let Some(properties) = &object.properties {
+            for key in properties.keys().sorted() {
+                fields.push(self.object_property(
+                    key,
+                    &properties[key],
+                    required.contains(key),
+                    name,
+                )?);
+            }
+        }
+        Ok(quote! {
+            #description
+            #derives
+            #[serde(rename_all = "camelCase")]
+            pub struct #struct_name {
+                #(#fields)*
+            }
+        })
+    }
+    fn object_property(
+        &self,
+        name: &str,
+        property: &LexObjectProperty,
+        is_required: bool,
+        object_name: &str,
+    ) -> Result<TokenStream> {
+        let (description, field_type) = match property {
+            LexObjectProperty::Ref(r#ref) => self.ref_type(r#ref)?,
+            LexObjectProperty::Union(union) => self.union_type(
+                union,
+                format!(
+                    "{}{}Enum",
+                    object_name.to_pascal_case(),
+                    name.to_pascal_case()
+                )
+                .as_str(),
+            )?,
+            LexObjectProperty::Bytes(bytes) => self.bytes_type(bytes)?,
+            LexObjectProperty::CidLink(cid_link) => self.cid_link_type(cid_link)?,
+            LexObjectProperty::Array(array) => {
+                let description = self.description(&array.description);
+                let (_, item_type) = match &array.items {
+                    LexArrayItem::Integer(integer) => self.integer_type(integer)?,
+                    LexArrayItem::String(string) => self.string_type(string)?,
+                    LexArrayItem::Unknown(unknown) => self.unknown_type(unknown)?,
+                    LexArrayItem::CidLink(cid_link) => self.cid_link_type(cid_link)?,
+                    LexArrayItem::Ref(r#ref) => self.ref_type(r#ref)?,
+                    LexArrayItem::Union(union) => self.union_type(
+                        union,
+                        format!(
+                            "{}{}Item",
+                            object_name.to_pascal_case(),
+                            name.to_pascal_case()
+                        )
+                        .as_str(),
+                    )?,
+                    _ => unimplemented!("{:?}", array.items),
+                };
+                // TODO: must be determined
+                if item_type.is_empty() {
+                    return Ok(quote!());
+                }
+                (description, quote!(Vec<#item_type>))
+            }
+            LexObjectProperty::Blob(blob) => self.blob_type(blob)?,
+            LexObjectProperty::Boolean(boolean) => self.boolean_type(boolean)?,
+            LexObjectProperty::Integer(integer) => self.integer_type(integer)?,
+            LexObjectProperty::String(string) => self.string_type(string)?,
+            LexObjectProperty::Unknown(unknown) => self.unknown_type(unknown)?,
+        };
+        // TODO: must be determined
+        if field_type.is_empty() {
+            return Ok(quote!());
+        }
+        // TODO: other keywords?
+        let field_name = format_ident!(
+            "{}",
+            if name == "type" {
+                String::from("r#type")
+            } else {
+                name.to_snake_case()
+            }
+        );
+        Ok(if is_required {
+            quote! {
+                #description
+                pub #field_name: #field_type,
+            }
+        } else {
+            quote! {
+                #description
+                #[serde(skip_serializing_if = "Option::is_none")]
+                pub #field_name: Option<#field_type>,
+            }
+        })
+    }
+    fn string(&self, name: &str, string: &LexString) -> Result<TokenStream> {
+        let description = self.description(&string.description);
+        let string_name = format_ident!("{}", name.to_pascal_case());
+        Ok(quote! {
+            #description
+            pub type #string_name = String;
+        })
+    }
+    fn ref_type(&self, r#ref: &LexRef) -> Result<(TokenStream, TokenStream)> {
+        let description = self.description(&r#ref.description);
+        Ok((description, self::resolve_ref(&r#ref.r#ref, "main")?))
+    }
+    fn union_type(
+        &self,
+        union: &LexRefUnion,
+        enum_name: &str,
+    ) -> Result<(TokenStream, TokenStream)> {
+        let description = self.description(&union.description);
+        let enum_type_name = format_ident!("{}", enum_name);
+        // Use `Box` to avoid recursive.
+        Ok((description, quote!(Box<#enum_type_name>)))
+    }
+    fn bytes_type(&self, bytes: &LexBytes) -> Result<(TokenStream, TokenStream)> {
+        let description = self.description(&bytes.description);
+        // TODO
+        Ok((description, quote!()))
+    }
+    fn cid_link_type(&self, cid_link: &LexCidLink) -> Result<(TokenStream, TokenStream)> {
+        let description = self.description(&cid_link.description);
+        // TODO
+        Ok((description, quote!()))
+    }
+    fn blob_type(&self, blob: &LexBlob) -> Result<(TokenStream, TokenStream)> {
+        let description = self.description(&blob.description);
+        Ok((description, quote!(crate::blob::BlobRef)))
+    }
+    fn boolean_type(&self, boolean: &LexBoolean) -> Result<(TokenStream, TokenStream)> {
+        let description = self.description(&boolean.description);
+        Ok((description, quote!(bool)))
+    }
+    fn integer_type(&self, integer: &LexInteger) -> Result<(TokenStream, TokenStream)> {
+        let description = self.description(&integer.description);
+        // TODO: usize?
+        Ok((description, quote!(i32)))
+    }
+    fn string_type(&self, string: &LexString) -> Result<(TokenStream, TokenStream)> {
+        let description = self.description(&string.description);
+        // TODO: format, enum?
+        Ok((description, quote!(String)))
+    }
+    fn unknown_type(&self, unknown: &LexUnknown) -> Result<(TokenStream, TokenStream)> {
+        let description = self.description(&unknown.description);
+        Ok((description, quote!(crate::records::Record)))
+    }
+    fn description(&self, description: &Option<String>) -> TokenStream {
+        if let Some(description) = description {
+            quote!(#[doc = #description])
+        } else {
+            quote!()
+        }
+    }
+}
+
+pub(crate) fn refs_enum(
+    name: &str,
+    refs: &[String],
+    schema_id: Option<&String>,
+) -> Result<TokenStream> {
+    let is_record = schema_id.is_none();
+    let derives = self::derives()?;
+    let enum_name = format_ident!("{name}");
+    let mut variants = Vec::new();
+    for r#ref in refs {
+        let default = if is_record { "record" } else { "main" };
+        let path = self::resolve_ref(r#ref, default)?;
+        let rename = if r#ref.starts_with('#') {
+            format!(
+                "{}{}",
+                schema_id.expect("schema id must be specified"),
+                r#ref
+            )
+        } else {
+            r#ref.clone()
+        };
+        let s = path.to_string().replace(' ', "");
+        let mut parts = s
+            .strip_prefix("crate::")
+            .unwrap_or(&s)
+            .split("::")
+            .map(str::to_pascal_case)
+            .collect_vec();
+        if is_record {
+            parts.pop();
+        }
+        let name = format_ident!("{}", parts.join(""));
+        variants.push(quote! {
+            #[serde(rename = #rename)]
+            #name(#path)
+        });
+    }
+    Ok(quote! {
+        #derives
+        #[serde(tag = "$type")]
+        pub enum #enum_name {
+            #(#variants),*
+        }
+    })
+}
+
+pub(crate) fn traits_macro(traits: &[String]) -> Result<TokenStream> {
+    let mut paths = Vec::new();
+    let mut roots = HashSet::new();
+    for t in traits {
+        let parts = t.split('.').collect_vec();
+        roots.insert(format_ident!("{}", parts[0].to_snake_case()));
+        let basename = parts.last().unwrap();
+        let path = syn::parse_str::<Path>(&format!(
+            "{}::{}",
+            parts.iter().map(|s| s.to_snake_case()).join("::"),
+            basename.to_pascal_case()
+        ))?;
+        paths.push(quote! {
+            impl #path for $type {}
+        });
+    }
+    let roots = roots.into_iter().sorted().collect_vec();
+    Ok(quote! {
+        #[macro_export]
+        macro_rules! impl_traits {
+            ($type:ty) => {
+                use atrium_api::{#(#roots),*};
+                #(#paths)*
+            }
+        }
+    })
+}
+
+pub(crate) fn modules(names: &[String]) -> Result<TokenStream> {
+    let v = names
+        .iter()
+        .filter_map(|s| {
+            if s != "lib" {
+                let m = format_ident!("{s}");
+                Some(quote!(pub mod #m;))
+            } else {
+                None
+            }
+        })
+        .collect_vec();
+    Ok(quote!(#(#v)*))
+}
+
+fn derives() -> Result<TokenStream> {
+    let mut derives = Vec::new();
+    for derive in &[
+        "serde::Serialize",
+        "serde::Deserialize",
+        "Debug",
+        "Clone",
+        "PartialEq",
+        "Eq",
+    ] {
+        derives.push(syn::parse_str::<Path>(derive)?);
+    }
+    Ok(quote!(#[derive(#(#derives),*)]))
+}
+
+fn resolve_ref(r#ref: &str, default: &str) -> Result<TokenStream> {
+    let (namespace, def) = r#ref.split_once('#').unwrap_or((r#ref, default));
+    let path = syn::parse_str::<Path>(&if namespace.is_empty() {
+        def.to_pascal_case()
+    } else {
+        format!(
+            "crate::{}::{}",
+            namespace.split('.').map(str::to_snake_case).join("::"),
+            def.to_pascal_case()
+        )
+    })?;
+    Ok(quote!(#path))
+}
diff --git a/atrium-lex/src/lexicon.rs b/atrium-lex/src/lexicon.rs
index f128b9ba..f45862d8 100644
--- a/atrium-lex/src/lexicon.rs
+++ b/atrium-lex/src/lexicon.rs
@@ -200,6 +200,7 @@ pub enum LexXrpcParametersProperty {
 #[skip_serializing_none]
 #[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
 pub struct LexXrpcParameters {
+    pub description: Option<String>,
     pub required: Option<Vec<String>>,
     pub properties: HashMap<String, LexXrpcParametersProperty>,
 }
diff --git a/src/bin/lexgen.rs b/src/bin/lexgen.rs
index c2669c52..1fb41da8 100644
--- a/src/bin/lexgen.rs
+++ b/src/bin/lexgen.rs
@@ -1,7 +1,7 @@
-use std::path::PathBuf;
-
 use atrium_codegen::genapi;
 use clap::Parser;
+use std::path::PathBuf;
+use std::process::Command;
 
 #[derive(Parser, Debug)]
 struct Args {
@@ -14,8 +14,19 @@ struct Args {
 fn main() -> Result<(), Box<dyn std::error::Error>> {
     let args = Args::parse();
 
-    for prefix in ["app.bsky", "com.atproto"] {
-        genapi(&args.lexdir, &args.outdir, prefix)?;
+    let results = genapi(&args.lexdir, &args.outdir, &["app.bsky", "com.atproto"])?;
+    for path in &results {
+        match Command::new("rustfmt")
+            .arg("--edition")
+            .arg("2021")
+            .arg(path.as_ref())
+            .status()
+        {
+            Ok(status) if status.success() => {}
+            _ => {
+                eprintln!("Failed to run rustfmt on {}", path.as_ref().display());
+            }
+        }
     }
     Ok(())
 }


Test patch: