NeoDoc [A Content Format] and The Atmosphere

-- prelude

This post is written in NeoDoc to provide
an example of what the format looks like.

A version with syntax highlighting and 
live links is available >> here |
https://neodoc.style/blog/neodoc-and-the-atmosphere/ >>
if you'd like to read it that way. 


-- tldr

I believe content portability is critical 
to fulfilling the promise of a decentralized 
internet. After all, being able to move your 
content doesn't count for much if it doesn't
work anywhere else. You're implicitly 
locked-in, even if you're seemingly in 
control^^control^^.

A few years ago, I designed a plain-text 
format to replace Markdown on >> my sites | 
https://links.alanwsmith.com/ >>. 
It's called NeoDoc and it offers a potential 
solution for bringing portable, human-readable 
content to the Atmosphere.

You can learn more about it at
>> neodoc.style | https://neodoc.style/ >>


-- title

NeoDoc and The Atmosphere

Hey folks,

While I've been on Bluesky for a bit, I 
didn't really know about the Atmosphere until 
recently. The more I learn, the more it has 
my attention. I can't remember the last time 
I was this excited about new tech. 

My introduction was standard.site^^standard^^.
It made several appearances in my feed over 
the past few weeks. I jumped^^jump^^ on it.
It's the kind of stuff I dream about^^manifesto^^.

I wasn't entirely sure how content worked 
in standard.site and went looking for details. 
One thing the leaflet^^leaflet^^ post I found 
points out is that the lexicon is for content 
discovery and social features. But,

  -- blockquote/

  Importantly, [it] is not a standard for 
  site content.

  -- /blockquote


The only other^^other^^ post I've seen on a 
content standard for the Atmosphere has to do 
with a wordpress lexicon for publishing HTML. 


-- h2

The Contenders

I submit that HTML could work as a standardized 
content format. It's a battle tested standard 
that renders natively in browsers without 
modification. There are, however, a couple 
things that recommend against it.

  -- numbered/

  1. It's not friendly to write by hand. 
  Unless you're hard-core, it's not something 
  most folks are into.

  2. It's tough to standardize different 
  types of content. Microformats^^micro^^ 
  were an attempt. They never took off. 
  That's at least in part because they lock 
  the content into the rendering layer. You 
  can do all kinds of things with CSS, but 
  you're stuck with a specific set of elements 
  and have to set up a separate parser if 
  you want to use the data in them 
  independently. 

  -- /numbered

Markdown^^md^^ is another option. It's easy to 
learn and has huge market share in the developer 
community. While it's great for blog posts, 
it sucks for everything else. You can always 
roll your own HTML to do interesting work. 
But, you wind up back with its unwieldy 
nature and parsing complexity.

The key feature missing from Markdown
is the ability to define content types.
For example, say you want to make a page of 
book reviews with explicit styles for the 
title, author, rating, and your thoughts. 
There's no native way in Markdown to define 
a container that provides access to the 
individual pieces of data. 

About the best you can do is define specific
positions for each piece of information and 
write a custom parser to process and assemble 
them^^mdbook^^. Possible, but you'd be better 
off writing the HTML directly which leads 
back to the same issues. 


-- h2

Introducing NeoDoc

There are other content formats out there. 
I reviewed a bunch when I got fed up with 
Markdown and decided to switch to something 
else for >> my various project websites 
| https://links.alanwsmith.com/ >>. 
None of the alternatives offered the combination 
of flexibility and ease of use I was after. 
So, I designed a new format. It's called
NeoDoc and you're reading it right 
now^^maybe^^.

NeoDoc is designed to be simple to write
without sacrificing the power built into 
HTML. The format breaks down like this:


-- list/
-- h3: The Details

- NeoDocs are built from sections. Each 
one starts with two dashes and a name. For 
example, we're currently in a ``list``
section. 

Section names that don't end with a ``/``
keep going until the next section starts. 

Section names that have a ``/``at the end
can wrap other sections. They go until they 
hit the matching tag that closes them 
(e.g. the ``-- /list``for this section 
that you'll see below).

- Sections can have attributes like the
``-- h3: The Details``above. They're
available during rendering to do thing
like adding an ``H3``tag with specific 
text above a list (which is what this one 
does when this page is rendered to HTML).

- There's a pre-defined set of sections like:
``list``, ``checklist``, and ``numbered``. 
You can also make ad hoc sections simply by 
naming them. For example, you can make a 
``-- book-review``section.

- Custom sections can have attributes just 
like the pre-defined ones. So, we can make 
a book review like this:

  -- pre/

  -- book-review
  -- title: Dungeon Crawler Carl
  -- author: Matt Dinniman
  -- rating: 5 stars
  -- tags: fantasy

  Always trust the friends you've known
  since third grade when they recommend
  a book...

  -- /pre

- Inline formatting and shorthands are
available for spans of text. For example, 
you can wrap text in asterisks that
convert to HTML ``strong``tags during
rendering like:

**Alfa Bravo Charlie**

- Inline spans can also have attributes. 
For example, here's a ``class``attribute 
with the strong shorthand syntax:

**Alfa Bravo Charlie | class: green**


-- /list


That's it. 

Sections, spans, and attributes. 

A simple combination that turns out 
to be incredibly powerful. 


-- h2

Outro

I designed NeoDoc three years ago. It's 
currently embedded in my personal static 
site generator where it powers
>> something like three thousand pages | 
https://www.alanwsmith.com/neo-files/report >>.

The format feels like a natural fit for 
the Atmosphere. So, I'm extracting the 
tools to make them independently available. 
Once they're ready, I'll make them open 
source so anyone can use them.

I'm incredibly excited about the Atmosphere. 
I hope NeoDoc can become a part of it. 
Because, if I'm right, the ability to 
easily move the stuff we make to wherever 
we want it will be key to practical 
decentralization. I believe NeoDoc can 
be instrumental in making that happen. 

-alan




-- endnote

If you've got questions or feedback, 
I'm all ears:

>> @al9000.com |
https://bsky.app/profile/al9000.com >>


-- endnote

I'd love to see NeoDoc become an active
participant in the Atmosphere. However, it's 
way more important to me that general content 
gets standardized on __something__, regardless 
of what it is. 

There will always be a need for custom formats 
for specific applications. For everything else, 
if we can't move it, it fails the promise 
and potential of decentralization. 


-- endnote

I didn't get into it here, but the section 
and attribute approach NeoDoc uses effectively 
turn content into a free-form database. 

For example, you can aggregate all your
``-- book-review``content in one place. 
Or, build something like Goodreads by 
watching the fire hose for those sections 
and building social features around them
(name-spacing is, of course, recommended).

The content will vary in how messy it is.
That's a feature. Not a bug. We've been living
so long in systems that force our content
into database schemas that we've forgotten
what a personal touch feels like. 

NeoDoc provides structure for finding, 
grouping, and laying out content without 
forcing everything to fit rigid data 
structures that prioritize storage over 
creativity. 


-- endnote/

I also didn't get into how transforming
content works. At the high level, the 
reference NeoDoc app (when it's extracted 
from my static site generator) performs 
three functions:

  -- numbered/

  1. Takes a NeoDoc formatted input and 
  transforms it into a JSON formatted AST. 

  2. Transforms a NeoDoc AST into HTML 
  based on a standardized set of default 
  templates. 

  3. Accepts optional templates that override
  the defaults when generating output. 

  -- /numbered

Collectively, that means NeoDoc can be 
used out of the box to generate 
standardized HTML. App can override the 
templates to either supply their own 
or pass in templates from the content 
authors. The combination lets apps provide 
complete control over the output with
the option to pass that control on to
the authors. 

More details on templating will be in 
the docs. 

-- /endnote


-- endnote

Another thing Markdown suffers from is lack 
of an official standard. Different, 
competing standards have cropped up as a 
result. NeoDoc's development includes a 
standard in the form of a comprehensive 
test suite for use in validating conforming
processors. 


-- endnote

NeoDoc isn't a theoretical idea. I've
been using it in production on my site
for years. The fundamentals are solid. 
I expect feedback from other folks will
lead to some modifications during a 
beta period as more folks use it. But,
I don't foresee anything that would 
significantly change its potential. 

Work on extracting NeoDoc from my site 
generator is underway. I don't have a 
specific target date, but it won't be 
that long until it's ready for other 
folks to start poking at. 


-- footnote
-- id: control

It is, of course, possible to migrate 
data from one format to another. However, 
that's a non-trivial amount of friction 
most folks would need someone else to 
set up for them (e.g. most folks aren't 
going to build their own ETL systems).


-- footnote
-- id: standard

>> Standard.site | https://standard.site/ >>

The shared lexicons for long-form 
publishing on AT Protocol.


-- footnote
-- id: jump

I've still got some work to do to get 
standard.site connections up and running 
for my site. The requirement to verify
every page individually is more work
than I've got time for at the moment. 


-- footnote
-- id: manifesto

>>A Vision for the Web |
https://www.alanwsmith.com/en/2v/xa/cn/vj/>>
(originally titled "A Website Manifesto") 
is a draft where I kicked around ideas 
for a more interconnected web. 

Basically, I was trying to figure out
how to build the Atmosphere using
RSS.


-- footnote
-- id: leaflet

>> Leaflet, standard.site, and open 
social publishing! |
https://lab.leaflet.pub/3md4qsktbms24 >>
is a great intro to what standard.site is
all about and its integration into leaflet. 


-- footnote
-- id: other

>> Automatically syncing your blog to atproto 
and standard.site |
https://jola.dev/posts/automatically-syncing-your-blog-atproto-standard-site >>
which mentions the wordpress HTML lexicon. 

At least, I think it's referencing a lexicon. I'm 
not sure and don't yet know where to look to 
figure that out. 


-- footnote
-- id: micro

>> Microformats | https://indieweb.org/microformats >> 
The >> IndieWeb's | https://indieweb.org/ >> 
attempt at standardizing content that never quite 
made it.


-- footnote
-- id: md

>> Markdown | https://www.markdownguide.org/ >>
The de facto standard for static site generators
everywhere. Great at what it does, but limited 
in what it can achieve. 


-- footnote
-- id: mdbook

For example, you could set up a parser to pull the
title from an H2 and then put the author in an H3
with the text for the review below that. That
would work, but it's super brittle and doesn't
provide for expansion without rewriting the
parser and updated all the existing content. 


-- footnote
-- id: maybe

Assuming a processor wasn't used to render
this content that transformed the content 
to straight HTML.



-- metadata
-- created: 2026-08-03T16:22:00-04:00
-- published: 2026-08-04T16:08:00-04:00
-- id: 01/n7/1y/38
-- tags: neodoc
-- status: done

3 Likes

Welcome! There are a LOT of people with opinions on text formats here :stuck_out_tongue:

I have done terrible crimes with YAML frontmatter over the years!

3 Likes

Wonderful write-up. I think alongside this, there should be an effort to establish a common container format that provides a sufficiently extensible structure for metadata such as content format, language, authorship, rights, etc. I personally see MASL as fulfilling this role:

2 Likes

hehehe, yeah. I expect text formats are something you can ask ten people about and get twelve opinions. I guess you could say NeoDoc is the manifestation of mine. I figure I’ve already got the parser so I might as well offer it for consideration.

(At a minimum it’ll be a fun exercise to see if the way I think makes sense to other folks or if it only makes sense to me because I built it. :rofl:)

1 Like
-- title

Progress Update [2026-08-07]

I'm making good progress extracting the 
NeoDoc parser from my static site generator. 
And by "extracting", I really mean redoing 
it from scratch as a stand-alone library. 
The original code is much to intertwined 
with the generator to untangle in any 
meaningful way. 

I don't have an ETA yet. I'll be able 
to give more guidance in a few days. 

-a

-- metadata
-- created: 2026-08-07T07:51:00-04:00
-- published: 2026-08-07T09:16:00-04:00
-- tags: neodoc
-- title

Spoiler/Content-Warning Update

Part of the NeoDoc spec is a list of 
section types that include reference 
HTML templates and rendering expectations 
for output.

Two new section types have been added 
based on the discussion from
>> In Which A Book Lexicon is Born |
https://discourse.atmosphere.community/t/in-which-a-book-lexicon-is-born/1042 >>.

They are: Spoilers and Content Warnings.

There's also a new inline Spoiler tag.
The specific start/stop tokens are TBD, 
but it'll be something like:

  -- pre/

  This is ;;a spoiler;; to
  keep things a surprise.

  -- /pre


-- h2

The NeoDoc Advantage

The Spoiler and Content Warning sections
are prime examples of NeoDoc's ability to 
offer content portability to the Atmosphere.
Without NeoDoc (or something like it) the 
ability to migrate content with spoilers 
or warnings between apps is impractical 
at best.

For example, assuming the use of Markdown,
the two ways that come to mind for 
identifying spoiler and content-warning 
content in plain-text storage are: 


-- numbered/

1. Add custom Markdown tokens like: 

  -- pre/

  \```cw Content Warning Label Goes Here
  Everything in this section is
  behind a content warning.
  \```

  \```spoiler
  This is the content of a spoiler
  section.
  \```

  And ;;this text;; is an inline
  spoiler.

  -- /pre


2. Define specific HTML tag/class 
combinations and roll out to using them.
For example:

  -- pre/

    <section class="content-warning">
      <div class="label">
        Content Warning Label Goes Here
      </div>

      Everything in this section is
      behind a content warning. 

      Markdown parsers should be able 
      to automatically transform these
      blocks into paragraphs.

    </section>


    <section class="spoiler">

      Everything in this section is
      behind a spoiler interface. 

      Markdown parsers should be able 
      to automatically transform these
      blocks into paragraphs.

    </section>


    Here is <span class="spoiler">some
    spoiler text</span> that gets
    hidden.

  -- /pre

-- /numbered


In either case, every app that uses
the content must agree on the syntax/html 
in order to maintain functionality. 

That's a practical impossibility.
There's no realistic way to have portable
spoiler/content-warning content using
Markdown as a result. The same issue 
arises with any other format that doesn't 
have native spoiler or content-warning 
types.

With the feature built in to NeoDoc, 
apps don't have to invent or coordinate
on custom syntax. They simply use
what's already defined in the spec.


-- h2

Change Window

I've been using NeoDoc for three years
in my static site generator. No one else
has it yet. That provides a fantastic 
opportunity to refine its capabilities
to further support the Atmosphere while 
it's being extracted into its own library. 
The spoiler/content-warning is a perfect 
example. I hadn't thought of them
until the topic came up in the community.

What's nice about NeoDoc's format is
that no alterations to the parser are
necessary to accommodate the change. The
only modification is an update to the
spec to include the section types in the 
pre-defined list and supply their 
reference templates. 

A critical point is that these type of
adjustments can only be made before NeoDoc 
is actively in production. Once it is, it'll 
be like a lexicon where stability of the
spec is a requirement. (Further enhancements 
are still possible. They would just have 
to be a matter of community convention
with the possibility of optional addendum 
section type specs, but the parser
functionality won't change.)


-- h2

Outro

I'll end with my refrain: 

Without portable content the full promise 
of a decentralized internet can't be 
achieved. 

While you can move from one PDS to 
another, you're content is still locked 
into specific apps if no one else uses 
the format its stored in. Handling 
multiple formats is, of course, possible. 
But, it would be better spending time
on features that enhance app experience
rather than building ETLs. 

I believe moving content between apps
is more appealing to non-technical users
than being able to migrate their PDS.
While Markdown is portable, it's 
incredibly limited. At the epoch of
the Atmosphere, we should aim for
better. 

-a



-- endnote

Adding the inline spoiler tag __is__ 
a change to the parser. Those changes
are only possible before NeoDoc is
in production. Once the shorthand
tokens have been locked down no
new ones will be added since that
would break backwards compatibility.



-- metadata
-- created: 2026-08-07T07:53:00-04:00
-- published: 2026-08-07T10:16:00-04:00
-- tags: neodoc
1 Like

I just put up the initial draft of the docs. It’s mostly stubs, but it includes all the features.

feedback is welcome.

I’m reviewing inline shorthands as part of the process of pulling NeoDoc’s parser out of my static site generator. I’m pretty sure I’m going to move underscores (which are emphasis/italics in markdown) to identify underlines.

Some folks will have Very Strong Opinions about that. I’m okay with it. I prefer to give priority to the long term over the way we’ve done things in the past and underscores provide a way better visual representation of an underline.

With that switch, the shorthand set looks like this:

``a span of code``

<<custom|let's you make your own types>>

;;this is emphasis italics;;

^^footnote^^

@@footnote return link@@

!!highlight aka mark!!

((raw html goes here))

++image_path|alt text++

>>link text|url>>

**strong aka bold**

~~strike through~~

__underline__

Other than the underscore thing, I’m open to suggestions for using different tokens or if another/different functionality should have a shorthand assigned.