Open the studio

The open format

Your words live in your account.

When you publish with SkyPress, nothing gets locked inside SkyPress. Your writing is saved to your own AT Protocol account, in open formats any reader on the social web can understand. You can take it anywhere. Here’s exactly what we write, and why.

What gets written when you publish

Publishing creates a few records on your PDS (the data store behind your account):

The first two use the community standard.site lexicons, not anything SkyPress-specific, so other tools and readers that already speak them can pick up your writing too. The one format SkyPress actually owns is the block content tucked inside the document; that’s the part below.

One thing worth repeating: publishing also creates a public Bluesky post. We’ll always remind you before you hit publish :)

The format we own: blog.skypress.content.gutenberg

A WordPress Gutenberg block tree, the canonical content of a SkyPress document. Placed inside the open content union of a site.standard.document. Readers that don't understand this format should fall back to the document's textContent.

FieldTypeRequiredWhat it is
version integer yes Serialization version of the block tree. Bump only for breaking changes; non-breaking changes are additive. Currently 1.
blocks array yes The Gutenberg block tree exactly as produced by the editor's onSaveBlocks (NOT rendered HTML). Each item is a block node: { name: string, attributes: object, innerBlocks: block[] }, where name is the Gutenberg block name (e.g. core/paragraph). Items are typed unknown because block attributes are open-ended per block type.

This is the only lexicon SkyPress owns. If a reader doesn’t understand the format, it falls back to the document’s plain-text textContent, so your article is never unreadable. Here’s the full schema:

{
  "lexicon": 1,
  "id": "blog.skypress.content.gutenberg",
  "defs": {
    "main": {
      "type": "object",
      "description": "A WordPress Gutenberg block tree, the canonical content of a SkyPress document. Placed inside the open `content` union of a `site.standard.document`. Readers that don't understand this format should fall back to the document's `textContent`.",
      "required": [
        "version",
        "blocks"
      ],
      "properties": {
        "version": {
          "type": "integer",
          "description": "Serialization version of the block tree. Bump only for breaking changes; non-breaking changes are additive. Currently 1.",
          "minimum": 1
        },
        "blocks": {
          "type": "array",
          "description": "The Gutenberg block tree exactly as produced by the editor's `onSaveBlocks` (NOT rendered HTML). Each item is a block node: `{ name: string, attributes: object, innerBlocks: block[] }`, where `name` is the Gutenberg block name (e.g. `core/paragraph`). Items are typed `unknown` because block attributes are open-ended per block type.",
          "items": {
            "type": "unknown"
          }
        }
      }
    }
  }
}

What the blocks look like

The schema says blocks is “the block tree exactly as produced by the editor”, which is a bit abstract. So here’s a real one. This is the content object from a published recipe, Potato buns, one way, trimmed to its first heading and a two-item list:

{
  "$type": "blog.skypress.content.gutenberg",
  "version": 1,
  "blocks": [
    {
      "name": "core/heading",
      "attributes": {
        "level": 2,
        "content": "Ingredients"
      },
      "innerBlocks": []
    },
    {
      "name": "core/list",
      "attributes": {
        "ordered": false,
        "values": ""
      },
      "innerBlocks": [
        {
          "name": "core/list-item",
          "attributes": {
            "content": "600g T45 flour"
          },
          "innerBlocks": []
        },
        {
          "name": "core/list-item",
          "attributes": {
            "content": "200g warm milk"
          },
          "innerBlocks": []
        }
      ]
    }
  ]
}

Every block is the same little shape: a name (the Gutenberg block, like core/heading), an attributes object for its content and settings, and innerBlocks for anything nested inside it, which is how the list here holds its items. The same shape repeats all the way down. The $type tells any reader which format it’s looking at; everything else is just blocks. You can see the full record behind any article yourself with the “view record” link in its eyebrow :)

Want to run your own?

SkyPress is open source (GPL-2.0-or-later), and it’s only ever an editor, an OAuth client, and a public renderer, never a home for your data. Your writing already lives in your AT Protocol account, in the open records above, so nothing’s tied to this particular site.

If you’d rather not use skypress.blog, you can host your own copy. It’s an Astro app that deploys to Cloudflare; the only thing you need to set is a PUBLIC_SITE_URL, and the OAuth client metadata and redirect URIs adapt to wherever you put it. The code, and the setup steps, live in the repo: tangled.org/jeremy.herve.bzh/skypress. Fork it, send patches, or just have a read :)

Start writing