{
"id": "page.mooring.site",
"defs": {
"rgb": {
"type": "object",
"required": [
"r",
"g",
"b"
],
"properties": {
"b": {
"type": "integer",
"maximum": 255,
"minimum": 0
},
"g": {
"type": "integer",
"maximum": 255,
"minimum": 0
},
"r": {
"type": "integer",
"maximum": 255,
"minimum": 0
}
}
},
"main": {
"key": "any",
"type": "record",
"record": {
"type": "object",
"required": [
"createdAt"
],
"properties": {
"icon": {
"type": "blob",
"accept": [
"image/*"
],
"maxSize": 1000000,
"description": "Square image used as the site icon/favicon. Should be at least 256x256."
},
"name": {
"type": "string",
"maxLength": 5000,
"description": "Site title. When absent, renderers should fall back to the owner's profile displayName or handle.",
"maxGraphemes": 500
},
"theme": {
"ref": "#theme",
"type": "ref"
},
"labels": {
"refs": [
"com.atproto.label.defs#selfLabels"
],
"type": "union"
},
"sections": {
"type": "array",
"items": {
"refs": [
"#heroSection",
"#postsSection",
"#writingSection",
"#careerSection",
"#pagesSection"
],
"type": "union",
"closed": false
},
"maxLength": 50,
"description": "Ordered sections of the site, rendered top to bottom; order is array position. When absent, renderers should use a sensible default order based on which sources have data."
},
"createdAt": {
"type": "string",
"format": "datetime",
"description": "Client-declared timestamp when this record was created."
},
"description": {
"type": "string",
"maxLength": 30000,
"description": "Short description of the site, used for meta tags and previews.",
"maxGraphemes": 3000
},
"discoverable": {
"type": "boolean",
"description": "Default true when absent. When false, the renderer emits noindex directives for the site. Does not affect the public visibility of the underlying atproto records."
}
}
},
"description": "A Mooring site. Every field except createdAt is optional: an empty record is a valid site, and the renderer falls back to the owner's profile records and a default section order."
},
"theme": {
"type": "object",
"properties": {
"colors": {
"ref": "#colors",
"type": "ref"
},
"preset": {
"type": "string",
"description": "Named theme preset. Unknown values should fall back to the renderer's default preset.",
"knownValues": [
"classic"
]
}
},
"description": "Theme selection and overrides. All fields optional; renderer defaults apply."
},
"colors": {
"type": "object",
"properties": {
"accent": {
"refs": [
"#rgb"
],
"type": "union",
"closed": false,
"description": "Color used for links and button backgrounds."
},
"background": {
"refs": [
"#rgb"
],
"type": "union",
"closed": false,
"description": "Color used for content background."
},
"foreground": {
"refs": [
"#rgb"
],
"type": "union",
"closed": false,
"description": "Color used for content text."
},
"accentForeground": {
"refs": [
"#rgb"
],
"type": "union",
"closed": false,
"description": "Color used for button text."
}
},
"description": "Semantic color overrides, mirroring the role vocabulary of site.standard.theme.basic. Any subset may be set."
},
"heroSection": {
"type": "object",
"properties": {
"title": {
"type": "string",
"maxLength": 1280,
"description": "Heading override. When absent, renderers should fall back to profile data.",
"maxGraphemes": 128
},
"tagline": {
"type": "string",
"maxLength": 3000,
"description": "Short line under the heading. When absent, renderers should fall back to the profile description or sifa headline.",
"maxGraphemes": 300
},
"showAvatar": {
"type": "boolean",
"description": "Default true when absent."
}
},
"description": "Introductory section rendered from the owner's profile records (app.bsky.actor.profile, with id.sifa.profile.self as professional-context overlay when present)."
},
"pagesSection": {
"type": "object",
"properties": {
"pages": {
"type": "array",
"items": {
"type": "string",
"format": "at-uri"
},
"maxLength": 100,
"description": "Explicit ordered list of page records (AT-URIs) to show. Renderers should skip dangling references. When absent, all public pages are listed in a renderer-defined order."
},
"title": {
"type": "string",
"maxLength": 1280,
"maxGraphemes": 128
}
},
"description": "Listing of the site's authored page.mooring.page records."
},
"postsSection": {
"type": "object",
"properties": {
"limit": {
"type": "integer",
"maximum": 50,
"minimum": 1,
"description": "Maximum number of posts to display. Renderer default applies when absent."
},
"title": {
"type": "string",
"maxLength": 1280,
"maxGraphemes": 128
}
},
"description": "Recent microblog posts from the owner's app.bsky.feed.post collection."
},
"careerSection": {
"type": "object",
"properties": {
"parts": {
"type": "array",
"items": {
"type": "string",
"knownValues": [
"positions",
"education",
"skills",
"projects",
"certifications",
"publications"
]
},
"maxLength": 10,
"description": "Which parts of the sifa profile to render, in order. When absent, renderers should show the parts that have data, in a default order."
},
"title": {
"type": "string",
"maxLength": 1280,
"maxGraphemes": 128
}
},
"description": "Professional profile rendered from the owner's id.sifa.* records."
},
"writingSection": {
"type": "object",
"properties": {
"limit": {
"type": "integer",
"maximum": 50,
"minimum": 1,
"description": "Maximum number of documents to display. Renderer default applies when absent."
},
"title": {
"type": "string",
"maxLength": 1280,
"maxGraphemes": 128
},
"publication": {
"type": "string",
"format": "at-uri",
"description": "AT-URI of a site.standard.publication record to scope the listing to. When absent, renderers should list the owner's documents across publications."
}
},
"description": "Long-form writing from the owner's site.standard.document collection (with pub.leaflet.* legacy records as fallback)."
}
},
"$type": "com.atproto.lexicon.schema",
"lexicon": 1,
"description": "Configuration for a Mooring site. The record at rkey 'self' is the owner's default site; other rkeys are reserved for possible future multi-site support."
}