Skip to main content

Episode 3 — Writing your first piece

Engine installed, workspace green. Time to actually make something. In this
episode we write a real blog post — and once you've seen the anatomy of one
content item, every other type works the same way.

What a content item actually is

A content item is a directory, not a file. That trips people up at first,
so let's be concrete. A blog post named hello-world lives like this:

content/resources/blog/hello-world/ parts/ body/ meta.toml # the part's identity en.md # frontmatter + the actual writing

Three ideas in that little tree:

  • The item is the hello-world/ directory. Its name is the slug.
  • An item is built from one or more parts. A blog post has exactly one
    part, body. Richer types have more — a project has overview, goals,
    challenges, and so on. Each part is a subdirectory under parts/.
  • Inside a part, each language is its own file: en.md, zh.md. The
    prose lives there.

Frontmatter: the structured half

Every part body file opens with a YAML frontmatter block — the fenced ---
section. This is the structured data the engine reads into the database.
Here's a minimal, valid blog post:

--- slug: hello-world title: Hello, world kind: blog status: draft visibility: private excerpt: My very first post on a system I actually trust. tags: - first-post --- ## Hello, world This is the body. Plain markdown, write whatever you want.

Worth knowing about those fields:

  • slug, title, kind, status, visibility are required on a blog
    post. Leave one out and the engine raises a fatal error — it won't sync.
  • kind must match the type. A file under blog/ must say kind: blog. A
    mismatch is a fatal error on purpose — it stops misfiled content cold.
  • status defaults to draft, visibility to private. So a brand-new post
    is invisible by default. You opt into publishing, never out of it.
  • Everything else — excerpt, tags, category, is_featured — is
    optional. Add what you need, skip what you don't.

The single source of truth for every field of every type is SCHEMA.md at the
root of your content tree. When you forget what a project allows, that file
is the answer — not your memory.

meta.toml: the part's identity

Next to en.md sits meta.toml. It's small and you mostly leave it alone:

type = "body" shape = "prose" canonical_lang = "en"

type is the part's role, shape is prose for ordinary writing, and
canonical_lang is the source language for any language-neutral fields. There
will also be a part_id — a stable ULID the engine generates and owns.
Don't write part_id by hand; let the engine assign it. It's the
permanent identity of that part, and it stays put even if you rename the
directory.

The shortcut: let the CLI scaffold it

You can hand-build that directory tree, but you don't have to. The CLI
scaffolds a correct skeleton for you:

silan new blog hello-world

That creates the directory, the parts/body/ folder, a meta.toml with a
fresh part_id, and an en.md pre-filled with valid frontmatter. You open
en.md and start writing prose. No fighting the structure — it's already
right.

Validate as you go

Don't wait until the end to find out you broke something. After any edit:

silan lint

lint parses your tree and reports problems by severity — fatal (won't
sync: a missing required field, a bad enum value, a kind mismatch), warn
(suspicious but allowed), info (notes). Get to a clean lint and you know the
next step will work.

On linking pieces together

One feature worth meeting now: relations. In the frontmatter you can link an
item to another:

relations: - { type: documents, to: /projects/hello-world }

Items address each other by silan:// URI. Relation types include
documents, references, evolved_into, part_of. This is what turns a
folder of files into a connected graph of thought — the thing that made the
system worth building. You don't need it for your first post; just know it's
there.


You can now write a valid content item and lint it clean. It still lives only
on your disk, though. Final episode: turning these files into a live site —
and the one deliberate gate between a draft and the public.