<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/">
<channel>
<title>open.blog</title>
<link>https://open-blog-jtc.netlify.app/</link>
<description>The example site for open.blog: Markdown files in, a fast static site out. This is the starter content every new blog begins with.</description>
<language>en</language>
<atom:link href="https://open-blog-jtc.netlify.app/rss.xml" rel="self" type="application/rss+xml"/>
<generator>open.blog</generator>
<lastBuildDate>Sat, 24 Oct 2026 00:00:00 GMT</lastBuildDate>
<item>
<title>Executable code lessons, with a safe fallback</title>
<link>https://open-blog-jtc.netlify.app/posts/executable-code-lessons/</link>
<guid isPermaLink="true">https://open-blog-jtc.netlify.app/posts/executable-code-lessons/</guid>
<pubDate>Sat, 24 Oct 2026 00:00:00 GMT</pubDate>
<dc:creator>open.blog</dc:creator>
<category>tutorial</category>
<category>rust</category>
<category>web</category>
<description>Rust and browser lessons work out of the box; configured languages fail closed until a separate runner is enabled.</description>
<content:encoded><![CDATA[<p>open.blog keeps authored source readable before it adds any execution. Try changing this greeting;
without JavaScript, it is still an ordinary code block.</p>
<h2 id="rust-works-by-default">Rust works by default<a class="ob-heading-anchor" href="https://open-blog-jtc.netlify.app/posts/executable-code-lessons/#rust-works-by-default" aria-label="Link to this section">#</a></h2>
<figure class="ob-code-block ob-runnable-code"><figcaption class="ob-code-title">Rust · edit and run</figcaption><pre><code class="language-rust">fn main() {
    let traveler = &quot;Mira&quot;;
    println!(&quot;Welcome to the lantern gate, {traveler}!&quot;);
}
</code></pre><p class="ob-playground-link"><a href="https://play.rust-lang.org/?version=stable&amp;mode=debug&amp;edition=2021&amp;code=fn+main%28%29+%7B%0A++++let+traveler+%3D+%22Mira%22%3B%0A++++println%21%28%22Welcome+to+the+lantern+gate%2C+%7Btraveler%7D%21%22%29%3B%0A%7D%0A">Open in Rust Playground</a>.</p><p class="ob-portable-note">Run and edit this example on <a href="https://open-blog-jtc.netlify.app/posts/executable-code-lessons/">the original article</a>.</p></figure>
<h2 id="web-lessons-stay-local">Web lessons stay local<a class="ob-heading-anchor" href="https://open-blog-jtc.netlify.app/posts/executable-code-lessons/#web-lessons-stay-local" aria-label="Link to this section">#</a></h2>
<p>Web lessons stay in a dependency-free, opaque-origin preview:</p>
<figure class="ob-code-block ob-web-sandbox"><figcaption class="ob-code-title">Web · reveal the gate</figcaption><p class="ob-web-sandbox-label">HTML</p><pre><code class="language-html">&lt;button id=&quot;gate&quot;&gt;Reveal the gate&lt;/button&gt;
</code></pre><p class="ob-web-sandbox-label">CSS</p><pre><code class="language-css">button { padding: 0.75rem 1rem; color: rebeccapurple; }
</code></pre><p class="ob-web-sandbox-label">JavaScript</p><pre><code class="language-js">document.querySelector(&quot;#gate&quot;).onclick = (event) =&gt; { event.currentTarget.textContent = &quot;The gate opens&quot;; };
</code></pre><p class="ob-portable-note">Open the live preview on <a href="https://open-blog-jtc.netlify.app/posts/executable-code-lessons/">the original article</a>.</p></figure>
<h2 id="configured-languages-fail-closed">Configured languages fail closed<a class="ob-heading-anchor" href="https://open-blog-jtc.netlify.app/posts/executable-code-lessons/#configured-languages-fail-closed" aria-label="Link to this section">#</a></h2>
<p>The repository example intentionally does not configure an external runner. This Python fence
therefore stays static even though it opts into <code>runnable</code>; a site owner must explicitly allow
Python and deploy an isolated gateway first.</p>
<figure class="ob-code-block"><figcaption class="ob-code-title">Python · static until enabled</figcaption><pre><code class="language-python">name = input().strip() or "traveler"
print(f"Welcome, {name}!")
</code></pre></figure>
<p>That fail-closed behavior lets an author keep portable lesson source without silently turning the
blog or Admin server into a code-execution service.</p>
<p class="ob-participation"><a href="https://open-blog-jtc.netlify.app/posts/executable-code-lessons/#ob-discussion">Join the discussion on the original article</a>.</p>
]]></content:encoded>
</item>
<item>
<title>Zhalendor — The Gate of Embers</title>
<link>https://open-blog-jtc.netlify.app/posts/zhalendor-gate-of-embers/</link>
<guid isPermaLink="true">https://open-blog-jtc.netlify.app/posts/zhalendor-gate-of-embers/</guid>
<pubDate>Sat, 24 Oct 2026 00:00:00 GMT</pubDate>
<dc:creator>open.blog</dc:creator>
<category>animation</category>
<category>fantasy</category>
<category>behind-the-scenes</category>
<description>A fictional Lantern Gate Studios episode page demonstrating production status, credits, chapters, a transcript, and AI-assistance disclosure.</description>
<content:encoded><![CDATA[<aside class="ob-video-production" aria-label="Video production summary"><h2>Production notes</h2><dl><div><dt>Production</dt><dd>Season 1, episode 1</dd></div><div><dt>Status</dt><dd>editing</dd></div><div><dt>Credits</dt><dd>Story and direction by the Lantern Gate team; animation and edit by the episode crew</dd></div></dl></aside>
<p class="ob-embed-link ob-embed-youtube"><a href="https://www.youtube.com/watch?v=Zha1endor01">Zhalendor — The Gate of Embers on YouTube</a></p>
<aside class="ob-callout ob-callout-note" role="note"><p class="ob-callout-title"><strong>Note</strong></p>
<p>This is a fictional product example, not an actual Lantern Gate Studios release or production
credit. It is intended to be replaced with the studio's real words and media.</p>
</aside>
<p>Seven travelers arrive at a sealed mountain gate as an old ward begins to fail. This companion page
keeps the episode, production context, and accessible transcript in creator-owned Markdown.</p>
<h2 id="chapters">Chapters<a class="ob-heading-anchor" href="https://open-blog-jtc.netlify.app/posts/zhalendor-gate-of-embers/#chapters" aria-label="Link to this section">#</a></h2>
<ol class="ob-chapters" aria-label="Video chapters">
<li><a href="https://www.youtube.com/watch?v=Zha1endor01&amp;t=0s"><time datetime="PT0S">00:00</time></a> The road beneath the mountain</li>
<li><a href="https://www.youtube.com/watch?v=Zha1endor01&amp;t=42s"><time datetime="PT42S">00:42</time></a> A warning in the ash</li>
<li><a href="https://www.youtube.com/watch?v=Zha1endor01&amp;t=96s"><time datetime="PT96S">01:36</time></a> The gate answers</li>
<li><a href="https://www.youtube.com/watch?v=Zha1endor01&amp;t=148s"><time datetime="PT148S">02:28</time></a> Beyond the threshold</li>
</ol>
<h2 id="production-log">Production log<a class="ob-heading-anchor" href="https://open-blog-jtc.netlify.app/posts/zhalendor-gate-of-embers/#production-log" aria-label="Link to this section">#</a></h2>
<ul>
<li><input disabled="" type="checkbox" checked=""/>
Story beat and continuity review</li>
<li><input disabled="" type="checkbox" checked=""/>
Shot list and animatic</li>
<li><input disabled="" type="checkbox" checked=""/>
Voice and sound pass</li>
<li><input disabled="" type="checkbox"/>
Final color and accessibility review</li>
<li><input disabled="" type="checkbox"/>
Release copy and scheduled publication</li>
</ul>
<h2 id="shot-notes">Shot notes<a class="ob-heading-anchor" href="https://open-blog-jtc.netlify.app/posts/zhalendor-gate-of-embers/#shot-notes" aria-label="Link to this section">#</a></h2>
<p>The opening uses a wide silhouette before moving to individual reaction shots. The gate remains the
visual anchor, while ember light distinguishes forbidden magic from ordinary torchlight.</p>
<h2 id="transcript">Transcript<a class="ob-heading-anchor" href="https://open-blog-jtc.netlify.app/posts/zhalendor-gate-of-embers/#transcript" aria-label="Link to this section">#</a></h2>
<p><strong>Narrator:</strong> The mountain had no door on any map, but every road bent toward it.</p>
<p><strong>Mara:</strong> Nobody touches the seal until we know who lit those runes.</p>
<p><strong>Narrator:</strong> From the other side came a sound like a great chain falling through the dark.</p>
<p class="ob-participation">Comments are closed. <a href="https://open-blog-jtc.netlify.app/posts/zhalendor-gate-of-embers/#ob-discussion">Read the discussion on the original article</a>.</p>
]]></content:encoded>
</item>
<item>
<title>A wet morning on the ridge</title>
<link>https://open-blog-jtc.netlify.app/posts/a-wet-morning-on-the-ridge/</link>
<guid isPermaLink="true">https://open-blog-jtc.netlify.app/posts/a-wet-morning-on-the-ridge/</guid>
<pubDate>Fri, 23 Oct 2026 00:00:00 GMT</pubDate>
<dc:creator>open.blog</dc:creator>
<category>hiking</category>
<category>field-notes</category>
<category>stewardship</category>
<description>A working field-journal example with trail conditions, observations, an approximate route, and practical stewardship notes.</description>
<enclosure url="https://open-blog-jtc.netlify.app/images/misty-ridge-field-note.jpg" length="0" type="image/jpeg"/>
<content:encoded><![CDATA[<p>The rain stopped shortly before sunrise, but the woods kept dripping for most of the
morning. Water moved through every shallow channel beside the trail, and the first rocky
climb was slick enough to slow the pace.</p>
<aside class="ob-callout ob-callout-note" role="note"><p class="ob-callout-title"><strong>Note</strong></p>
<p>This is a fictional but realistic working example. Its location is deliberately
generalized, and its route drawing contains normalized illustration points—not latitude
and longitude.</p>
</aside>
<h2 id="route-notes">Route notes<a class="ob-heading-anchor" href="https://open-blog-jtc.netlify.app/posts/a-wet-morning-on-the-ridge/#route-notes" aria-label="Link to this section">#</a></h2>
<p>The lower trail crossed mixed hardwood forest before turning uphill through hemlock and
white pine. At roughly the halfway point, the path reached an exposed ledge where wind had
already dried the rock. Low cloud hid the farther hills, so I turned around at the next
junction instead of completing the longer loop.</p>
<p>The approximate route above is enough to show the shape and effort of the outing without
publishing a trailhead, campsite, or observation coordinate. For a real post, import a GPX
file in <strong>Field Review</strong> and choose the privacy mode before saving.</p>
<h2 id="field-observations">Field observations<a class="ob-heading-anchor" href="https://open-blog-jtc.netlify.app/posts/a-wet-morning-on-the-ridge/#field-observations" aria-label="Link to this section">#</a></h2>
<ul>
<li>Several red-backed salamanders were active beneath already-loose bark beside the path.
I left the bark in place and did not record a precise location.</li>
<li>Club moss was bright green across the shaded slope, while the exposed ridge vegetation
was already dormant.</li>
<li>Fresh boot widening was visible around two muddy sections. Staying in the center of the
tread kept the disturbed area from spreading farther into the understory.</li>
<li>A small drainage crossing was carrying clear water with no visible sediment plume.</li>
</ul>
<h2 id="trail-and-access-conditions">Trail and access conditions<a class="ob-heading-anchor" href="https://open-blog-jtc.netlify.app/posts/a-wet-morning-on-the-ridge/#trail-and-access-conditions" aria-label="Link to this section">#</a></h2>
<p>The first kilometer was broad and gently graded. Beyond the stream crossing, roots, wet
slabs, and two short step-ups made the route unsuitable for wheels and potentially difficult
for hikers with limited balance. Cell service was intermittent below the ridge. There was
no reliable water source after the crossing.</p>
<h2 id="stewardship-note">Stewardship note<a class="ob-heading-anchor" href="https://open-blog-jtc.netlify.app/posts/a-wet-morning-on-the-ridge/#stewardship-note" aria-label="Link to this section">#</a></h2>
<p>One fist-sized branch had fallen across the drainage outlet near the lower switchback. I
moved only the loose branch, leaving embedded rocks and the channel itself untouched. The
larger muddy section would benefit from assessment by the trail steward rather than an
informal reroute.</p>
<h2 id="what-i-would-bring-next-time">What I would bring next time<a class="ob-heading-anchor" href="https://open-blog-jtc.netlify.app/posts/a-wet-morning-on-the-ridge/#what-i-would-bring-next-time" aria-label="Link to this section">#</a></h2>
<ul>
<li>Trekking poles for the wet descent</li>
<li>A small towel for camera gear</li>
<li>Offline trail information downloaded before leaving</li>
<li>A few extra minutes to document the widening tread for the local steward</li>
</ul>
<p>Field journals work best when they record what was actually observed, distinguish estimates
from measurements, and reveal no more location detail than the story needs.</p>
<p class="ob-participation"><a href="https://open-blog-jtc.netlify.app/posts/a-wet-morning-on-the-ridge/#ob-discussion">Join the discussion on the original article</a>.</p>
]]></content:encoded>
</item>
<item>
<title>Research posts and contributor credits</title>
<link>https://open-blog-jtc.netlify.app/posts/research-and-contributor-credits/</link>
<guid isPermaLink="true">https://open-blog-jtc.netlify.app/posts/research-and-contributor-credits/</guid>
<pubDate>Mon, 16 Feb 2026 00:00:00 GMT</pubDate>
<dc:creator>Example Author</dc:creator>
<category>research</category>
<category>guide</category>
<category>collaboration</category>
<description>A working example of research metadata, ordered authorship, contributor roles, references, and the Admin Studio workflow.</description>
<content:encoded><![CDATA[<aside class="ob-contributions" aria-labelledby="ob-contributions-title">
<h2 id="ob-contributions-title" class="ob-contributions-title">Contributions</h2>
<ul>
<li><div><span class="ob-contributor-name">Example Author</span><span class="ob-contributor-roles">Author, Conceptualization, Writing – original draft</span></div></li>
<li><div><span class="ob-contributor-name">Example Editor</span><span class="ob-contributor-roles">Editor, Writing – review &amp; editing</span></div></li>
</ul>
</aside>
<aside class="ob-work-meta" aria-label="Research work details"><dl><div><dt>Reuse</dt><dd><a href="https://creativecommons.org/licenses/by/4.0/">License</a></dd></div></dl></aside>
<h2 id="abstract">Abstract<a class="ob-heading-anchor" href="https://open-blog-jtc.netlify.app/posts/research-and-contributor-credits/#abstract" aria-label="Link to this section">#</a></h2>
<p>This working example shows how a portable Markdown article can publish research-oriented
metadata and credit more than one person without putting identity data in front matter. The
post selects the <code>research</code> profile, while an adjacent JSON sidecar supplies ordered authorship
and controlled contributor roles.</p>
<h2 id="follow-the-source-files">Follow the source files<a class="ob-heading-anchor" href="https://open-blog-jtc.netlify.app/posts/research-and-contributor-credits/#follow-the-source-files" aria-label="Link to this section">#</a></h2>
<p>Three files make the demonstration work:</p>
<ol>
<li><code>openblog.json</code> registers the reusable <code>example-author</code> and <code>example-editor</code> identities.</li>
<li>This Markdown file contains the article, license, Abstract, and References sections.</li>
<li><code>2026-02-16-research-and-contributor-credits.credits.json</code> connects those identities to
this work with Crossref and CRediT roles.</li>
</ol>
<p>The identities are deliberately synthetic and their ORCID fields are empty. Replace them with
real people and add only identifiers those people actually control. Manually entered ORCID iDs
remain visibly labeled as unauthenticated.</p>
<h2 id="what-to-inspect">What to inspect<a class="ob-heading-anchor" href="https://open-blog-jtc.netlify.app/posts/research-and-contributor-credits/#what-to-inspect" aria-label="Link to this section">#</a></h2>
<p>Open this post in Admin Studio to see the same data from an author's point of view:</p>
<ul>
<li><strong>Settings → Credit contributors and roles</strong> preserves credit order and exposes controlled
roles.</li>
<li><strong>Evidence</strong> reports the research structure and bounded reference links below.</li>
<li><strong>Site preview</strong> renders the production byline, work details, and Contributions panel.</li>
<li><strong>Social</strong> uses the same publishing-engine metadata as the generated page.</li>
</ul>
<p>After <code>openblog build</code>, inspect this page, <code>rss.xml</code>, <code>feed.json</code>, and the page's JSON-LD.
Only the Crossref author appears in author-only metadata; both people and all their roles remain
visible in the Contributions panel.</p>
<h2 id="references">References<a class="ob-heading-anchor" href="https://open-blog-jtc.netlify.app/posts/research-and-contributor-credits/#references" aria-label="Link to this section">#</a></h2>
<ol>
<li><a href="https://credit.niso.org/">CRediT role taxonomy</a></li>
<li><a href="https://www.crossref.org/documentation/schema-library/markup-guide-metadata-segments/contributors/">Crossref contributor guidance</a></li>
</ol>
<p class="ob-participation"><a href="https://open-blog-jtc.netlify.app/posts/research-and-contributor-credits/#ob-discussion">Join the discussion on the original article</a>.</p>
]]></content:encoded>
</item>
<item>
<title>Safely cross-posting your blog</title>
<link>https://open-blog-jtc.netlify.app/posts/automated-cross-posting/</link>
<guid isPermaLink="true">https://open-blog-jtc.netlify.app/posts/automated-cross-posting/</guid>
<pubDate>Mon, 09 Feb 2026 00:00:00 GMT</pubDate>
<dc:creator>open.blog</dc:creator>
<category>guide</category>
<description>Publish here first, then send reviewable, canonical copies to DEV, Hashnode, Medium, Ghost, or WordPress.</description>
<content:encoded><![CDATA[<p>Publishing in more than one community can help readers find your work, but your blog
should remain the source of truth. The dependable sequence is:</p>
<ol>
<li>publish the article on your open.blog site;</li>
<li>make sure its final URL is live;</li>
<li>create drafts on the other platforms;</li>
<li>set each copy's canonical URL back to the open.blog article;</li>
<li>review the formatting, then publish the copies.</li>
</ol>
<p>The canonical URL tells search engines which copy is the original. Deploying that URL
first also prevents every destination from pointing at a page that does not exist yet.</p>
<h2 id="start-with-the-feeds">Start with the feeds<a class="ob-heading-anchor" href="https://open-blog-jtc.netlify.app/posts/automated-cross-posting/#start-with-the-feeds" aria-label="Link to this section">#</a></h2>
<p>Every open.blog site can expose full-content RSS at <code>/rss.xml</code> and JSON Feed at
<code>/feed.json</code>. Enable <code>feeds.rss</code>, <code>feeds.json</code>, and <code>feeds.fullContent</code> in
<code>openblog.json</code>. A feed automation service can then watch either URL and create a draft
when a new post appears.</p>
<p>Before connecting one, confirm that its destination action can:</p>
<ul>
<li>create a draft instead of publishing immediately;</li>
<li>set the original article URL as canonical;</li>
<li>update the same remote article rather than create a duplicate.</li>
</ul>
<p>If it cannot do those things, use the destination's API or import flow instead.</p>
<h2 id="pick-the-right-setup-for-each-platform">Pick the right setup for each platform<a class="ob-heading-anchor" href="https://open-blog-jtc.netlify.app/posts/automated-cross-posting/#pick-the-right-setup-for-each-platform" aria-label="Link to this section">#</a></h2>
<ul>
<li><strong>Hashnode:</strong> its official GitHub Action can publish repository Markdown and supports
drafts, dry runs, and canonical URLs. API publishing now requires a Hashnode Pro
publication.</li>
<li><strong>DEV Community:</strong> its API accepts Markdown, supports drafts, and has a
<code>canonical_url</code> field. Save the returned article ID so future runs update the same
post.</li>
<li><strong>Medium:</strong> use <strong>Import a story</strong> after the original is live. Medium does not accept
new API integrations; its importer adds the original URL as canonical automatically.</li>
<li><strong>Ghost:</strong> its Admin API supports drafts and custom canonical URLs. Keep the Admin API
key on a trusted server or in CI, never in browser JavaScript.</li>
<li><strong>WordPress:</strong> its REST API supports drafts, but core WordPress has no portable field
for an external canonical. Only syndicate automatically if your particular SEO plugin
or site configuration exposes and verifies one.</li>
</ul>
<p>The repository's
<a href="https://github.com/journey-to-code-org/open.blog/blob/main/docs/cross-posting.md">complete cross-posting guide</a>
walks through credentials, API requests, CI safety, updating instead of duplicating, and
the official documentation for each platform. It also includes a complete GitHub
Actions template that waits for deployment, verifies the canonical URL, and creates or
updates a DEV draft from the deployed JSON Feed.</p>
<h2 id="keep-publishing-credentials-private">Keep publishing credentials private<a class="ob-heading-anchor" href="https://open-blog-jtc.netlify.app/posts/automated-cross-posting/#keep-publishing-credentials-private" aria-label="Link to this section">#</a></h2>
<p>Store tokens as encrypted CI secrets. Never put one in Markdown front matter, the
generated site, or code that runs in a reader's browser. Start every integration in
draft mode and test it with one disposable article.</p>
<p>Once that works, automation can handle the repetitive copying while you keep the final
review. Your Markdown stays authoritative, every public copy points home, and a failure
on one community does not prevent the original article from reaching your readers.</p>
<p class="ob-participation"><a href="https://open-blog-jtc.netlify.app/posts/automated-cross-posting/#ob-discussion">Join the discussion on the original article</a>.</p>
]]></content:encoded>
</item>
<item>
<title>Recipes, too: lemon garlic pasta</title>
<link>https://open-blog-jtc.netlify.app/posts/recipes-for-cooks/</link>
<guid isPermaLink="true">https://open-blog-jtc.netlify.app/posts/recipes-for-cooks/</guid>
<pubDate>Mon, 02 Feb 2026 00:00:00 GMT</pubDate>
<dc:creator>open.blog</dc:creator>
<category>recipe</category>
<category>guide</category>
<description>open.blog is not only for code. Mark a post as a recipe and readers get a recipe card, servings scaling, checklists, timers, cook mode, and a print view.</description>
<content:encoded><![CDATA[<section class="ob-recipe-card" aria-label="Recipe summary">
<dl class="ob-recipe-facts"><div><dt>Prep</dt><dd><time datetime="PT10M">10 min</time></dd></div><div><dt>Cook</dt><dd><time datetime="PT15M">15 min</time></dd></div><div><dt>Total</dt><dd><time datetime="PT25M">25 min</time></dd></div><div><dt>Serves</dt><dd>4</dd></div><div><dt>Cuisine</dt><dd>Italian</dd></div><div><dt>Course</dt><dd>Dinner</dd></div></dl>
</section>
<p>open.blog is not only for code. Add <code>profile: recipe</code> to a post's front matter, put the
ingredients in a list under an <code>## Ingredients</code> heading and the steps in a list under a
<code>## Steps</code> heading, and the post becomes a recipe:</p>
<ul>
<li>A summary card with the times and servings, and a "Jump to recipe" link.</li>
<li>Buttons that scale the amount at the start of each ingredient to more or fewer servings.</li>
<li>Checkboxes to tick off ingredients and steps (remembered on the reader's device).</li>
<li>Timers: any time in a step, like "10 minutes", starts a countdown when tapped.</li>
<li>Cook mode keeps the screen awake, and "Print recipe" prints just the recipe.</li>
<li>Search engines get schema.org recipe data; with a photo, the post can appear as a recipe result.</li>
</ul>
<p>Start a new one with <code>openblog new "Lemon garlic pasta" --recipe</code>. This post is a working
example; try the buttons above.</p>
<aside class="ob-callout ob-callout-tip" role="note"><p class="ob-callout-title"><strong>Tip</strong></p>
<p>Save a cup of the pasta water before you drain it. Its starch makes the sauce glossy.</p>
</aside>
<section class="ob-recipe-part ob-recipe-ingredients">
<h2 id="ingredients">Ingredients<a class="ob-heading-anchor" href="https://open-blog-jtc.netlify.app/posts/recipes-for-cooks/#ingredients" aria-label="Link to this section">#</a></h2>
<ul class="ob-recipe-list ob-ingredients">
<li>400 g spaghetti</li>
<li>3 tbsp olive oil</li>
<li>4 cloves garlic, thinly sliced</li>
<li>1 1/2 lemons, zested and juiced</li>
<li>1/2 cup grated parmesan, plus more to serve</li>
<li>1 handful parsley, chopped</li>
<li>Salt and black pepper, to taste</li>
</ul>
</section>
<section class="ob-recipe-part ob-recipe-steps">
<h2 id="steps">Steps<a class="ob-heading-anchor" href="https://open-blog-jtc.netlify.app/posts/recipes-for-cooks/#steps" aria-label="Link to this section">#</a></h2>
<ol class="ob-recipe-list ob-steps">
<li>Bring a large pot of salted water to the boil and cook the spaghetti for 9 minutes.</li>
<li>Meanwhile, warm the olive oil in a wide pan over low heat and cook the garlic for
2-3 minutes, until soft but not brown.</li>
<li>Save a cup of the pasta water, then drain the spaghetti and add it to the pan.</li>
<li>Add the lemon zest and juice, the parmesan, and a splash of pasta water. Toss for
1 minute, until glossy, adding more water if it looks dry.</li>
<li>Season, scatter over the parsley, and serve with more parmesan.</li>
</ol>
</section>
<h2 id="notes">Notes<a class="ob-heading-anchor" href="https://open-blog-jtc.netlify.app/posts/recipes-for-cooks/#notes" aria-label="Link to this section">#</a></h2>
<p>The front matter for this post:</p>
<pre><code class="language-yaml">profile: recipe
servings: 4
prep: 10 min
cook: 15 min
cuisine: Italian
course: Dinner
</code></pre>
<p>Times can be written as <code>15 min</code>, <code>1 hr 30 min</code>, or <code>1:30</code>; something like <code>overnight</code>
is shown as written. Use <code>makes: 12 cookies</code> to say what a recipe makes, alongside
<code>servings</code> if readers should be able to scale it.</p>
<p class="ob-participation"><a href="https://open-blog-jtc.netlify.app/posts/recipes-for-cooks/#ob-discussion">Join the discussion on the original article</a>.</p>
]]></content:encoded>
</item>
<item>
<title>Publishing and scheduling</title>
<link>https://open-blog-jtc.netlify.app/posts/publishing-and-scheduling/</link>
<guid isPermaLink="true">https://open-blog-jtc.netlify.app/posts/publishing-and-scheduling/</guid>
<pubDate>Mon, 26 Jan 2026 00:00:00 GMT</pubDate>
<dc:creator>open.blog</dc:creator>
<category>guide</category>
<description>Build the site, host it anywhere, keep a draft private, and schedule a post for later.</description>
<content:encoded><![CDATA[<h2 id="build-and-host">Build and host<a class="ob-heading-anchor" href="https://open-blog-jtc.netlify.app/posts/publishing-and-scheduling/#build-and-host" aria-label="Link to this section">#</a></h2>
<pre><code class="language-sh">openblog build
</code></pre>
<p>writes a complete static site to <code>dist/</code>: pages, RSS and JSON feeds, a sitemap, a search
index, and the assets. Upload that folder to any static host, or run <code>openblog serve</code> to
host it yourself.</p>
<h2 id="drafts">Drafts<a class="ob-heading-anchor" href="https://open-blog-jtc.netlify.app/posts/publishing-and-scheduling/#drafts" aria-label="Link to this section">#</a></h2>
<p><code>draft: true</code> keeps a post out of every build and feed. <code>openblog serve --drafts</code> previews
drafts locally. The admin editor shows drafts with their own badge.</p>
<h2 id="scheduling">Scheduling<a class="ob-heading-anchor" href="https://open-blog-jtc.netlify.app/posts/publishing-and-scheduling/#scheduling" aria-label="Link to this section">#</a></h2>
<p>Give a post a date in the future and it is <em>scheduled</em>:</p>
<pre><code class="language-yaml">date: 2026-12-25T09:00:00Z
</code></pre>
<p>Scheduled posts stay out of the pages, feeds, sitemap, and search index. When the time
comes, <code>openblog serve</code> rebuilds by itself. On a static host, any <code>openblog build</code> after
that time publishes it, so a daily build (a cron job or a scheduled workflow) is enough.</p>
<h2 id="the-admin-editor">The admin editor<a class="ob-heading-anchor" href="https://open-blog-jtc.netlify.app/posts/publishing-and-scheduling/#the-admin-editor" aria-label="Link to this section">#</a></h2>
<p>For editing from a browser, including on the server that hosts the blog:</p>
<pre><code class="language-sh">openblog user add you
openblog serve --admin
</code></pre>
<p>Then open <code>/admin</code>. It writes the same Markdown files, so you can mix both ways of
working. <code>docs/admin.md</code> covers running it safely on the public internet.</p>
<h2 id="feeds-and-cross-posting">Feeds and cross-posting<a class="ob-heading-anchor" href="https://open-blog-jtc.netlify.app/posts/publishing-and-scheduling/#feeds-and-cross-posting" aria-label="Link to this section">#</a></h2>
<p><code>/rss.xml</code> carries the full post HTML and <code>/feed.json</code> is JSON Feed 1.1. Most newsletter
and cross-posting tools accept either. If you republish a post elsewhere, set the copy's
canonical URL to its address here; for a post that was first published elsewhere, set
<code>canonical:</code> in its front matter.</p>
<p>Continue with <a href="https://open-blog-jtc.netlify.app/posts/automated-cross-posting/">Safely cross-posting your blog</a> for a
review-first workflow covering Hashnode, DEV, Medium, Ghost, and WordPress.</p>
<p>That is the whole workflow. Delete this series when your own posts arrive, or keep it as
a reference.</p>
<p class="ob-participation"><a href="https://open-blog-jtc.netlify.app/posts/publishing-and-scheduling/#ob-discussion">Join the discussion on the original article</a>.</p>
]]></content:encoded>
</item>
<item>
<title>Tags and series</title>
<link>https://open-blog-jtc.netlify.app/posts/tags-and-series/</link>
<guid isPermaLink="true">https://open-blog-jtc.netlify.app/posts/tags-and-series/</guid>
<pubDate>Mon, 19 Jan 2026 00:00:00 GMT</pubDate>
<dc:creator>open.blog</dc:creator>
<category>guide</category>
<description>Tags group posts by topic. Series put posts in reading order, and each series can have its own theme.</description>
<content:encoded><![CDATA[<h2 id="tags">Tags<a class="ob-heading-anchor" href="https://open-blog-jtc.netlify.app/posts/tags-and-series/#tags" aria-label="Link to this section">#</a></h2>
<p>List them in the front matter. Each tag gets a page at <code>/tags/&lt;slug&gt;/</code>, and <code>/tags/</code> lists
them all with counts. Tags are matched case-insensitively, so <code>Rust</code> and <code>rust</code> are one tag.</p>
<pre><code class="language-yaml">tags:
  - guide
  - rust
</code></pre>
<h2 id="series">Series<a class="ob-heading-anchor" href="https://open-blog-jtc.netlify.app/posts/tags-and-series/#series" aria-label="Link to this section">#</a></h2>
<p>A series is a file in <code>content/series/</code>. This one is <code>content/series/getting-started.md</code>:</p>
<pre><code class="language-yaml">---
name: Getting started
description: Three short parts ...
theme: demo        # every post in the series renders with this theme
order: 1           # position on the /series/ page
---
Optional Markdown shown at the top of the series page.
</code></pre>
<p>A post joins a series with <code>series: getting-started</code>. Parts are ordered by <code>seriesOrder</code>,
or by date when it is missing. The post page then shows "Part 2 of 3", previous and next
links, and a list of all parts. If you reference a series that has no file, open.blog
creates it from the slug and warns you.</p>
<h2 id="themes-per-series">Themes per series<a class="ob-heading-anchor" href="https://open-blog-jtc.netlify.app/posts/tags-and-series/#themes-per-series" aria-label="Link to this section">#</a></h2>
<p>Set <code>theme:</code> on a series and all of its posts switch theme, including this one. A single
post can override with <code>theme:</code> of its own. The themes available are the folders under
<code>themes/</code>; run <code>openblog themes</code> to list them. See <code>docs/themes.md</code> for how a theme is
built from design tokens, and <code>docs/theme-components.md</code> for the heading effect this
series is using.</p>
<p>Next: <a href="https://open-blog-jtc.netlify.app/posts/publishing-and-scheduling/">Publishing and scheduling</a>.</p>
<p class="ob-participation"><a href="https://open-blog-jtc.netlify.app/posts/tags-and-series/#ob-discussion">Join the discussion on the original article</a>.</p>
]]></content:encoded>
</item>
<item>
<title>Writing a post</title>
<link>https://open-blog-jtc.netlify.app/posts/writing-a-post/</link>
<guid isPermaLink="true">https://open-blog-jtc.netlify.app/posts/writing-a-post/</guid>
<pubDate>Mon, 12 Jan 2026 00:00:00 GMT</pubDate>
<dc:creator>open.blog</dc:creator>
<category>guide</category>
<category>markdown</category>
<description>What goes in a post file, which Markdown features work, and how images and code blocks are handled.</description>
<content:encoded><![CDATA[<p>A post is a Markdown file in <code>content/posts/</code>. The file name can start with a date
(<code>2026-01-12-writing-a-post.md</code>); the rest becomes the slug, so this post lives at
<code>/posts/writing-a-post/</code>. Add <code>slug:</code> to the front matter to choose a different one.</p>
<h2 id="front-matter">Front matter<a class="ob-heading-anchor" href="https://open-blog-jtc.netlify.app/posts/writing-a-post/#front-matter" aria-label="Link to this section">#</a></h2>
<pre><code class="language-yaml">---
title: Writing a post
subtitle: Optional. A one-line subheading shown under the title.
date: 2026-01-12           # or a full time: 2026-01-12T09:30:00Z
tags: [guide, markdown]    # inline lists work too
description: Optional. Used in feeds and search results.
cover: /images/cover.png   # optional; the first image in the body is the fallback
draft: false
---
</code></pre>
<p>Dates without a time are midnight UTC. A post dated in the future is <em>scheduled</em> and stays
hidden until that moment (part three has the details).</p>
<h2 id="markdown-that-works">Markdown that works<a class="ob-heading-anchor" href="https://open-blog-jtc.netlify.app/posts/writing-a-post/#markdown-that-works" aria-label="Link to this section">#</a></h2>
<p>CommonMark plus the GitHub extensions: tables, task lists, footnotes, and strikethrough.
Headings get ids and anchor links, so <code>#markdown-that-works</code> links here.</p>
<table><thead><tr><th>Feature</th><th>Syntax</th></tr></thead><tbody>
<tr><td>Task list</td><td><code>- [x] done</code></td></tr>
<tr><td>Footnote</td><td><code>text[^1]</code></td></tr>
<tr><td>Strikethrough</td><td><code>~~old~~</code></td></tr>
</tbody></table>
<ul>
<li><input disabled="" type="checkbox" checked=""/>
Write the post</li>
<li><input disabled="" type="checkbox"/>
Publish it</li>
</ul>
<p>Callouts draw attention to a note, a tip, or a warning:</p>
<aside class="ob-callout ob-callout-tip" role="note"><p class="ob-callout-title"><strong>Tip</strong></p>
<p>Write <code>&gt; [!NOTE]</code>, <code>&gt; [!TIP]</code>, <code>&gt; [!IMPORTANT]</code>, <code>&gt; [!WARNING]</code>, or <code>&gt; [!CAUTION]</code>
on the first line of a quote.</p>
</aside>
<p>Regular code blocks are read-only: they keep the original syntax colouring, line numbers,
highlighted lines, and copy button. This one demonstrates that decorative presentation:</p>
<figure class="ob-code-block"><figcaption class="ob-code-title">Read-only example · src/lib.rs</figcaption><pre><code class="language-rust" data-highlight-lines="2">pub fn greeting(name: &amp;str) -&gt; String {
    format!("Hello, {name}!")
}
</code></pre></figure>
<p>Add <code>runnable</code> only when readers should be able to edit and execute a self-contained Rust
example. A runnable block deliberately becomes an editor with controls and inline output:</p>
<figure class="ob-code-block ob-runnable-code"><figcaption class="ob-code-title">Live example · try changing the name</figcaption><pre><code class="language-rust" data-line-numbers="true" data-highlight-lines="2">fn main() {
    let name = &quot;reader&quot;;
    println!(&quot;Hello, {name}!&quot;);
}
</code></pre><p class="ob-portable-note">Run and edit this example on <a href="https://open-blog-jtc.netlify.app/posts/writing-a-post/">the original article</a>.</p></figure>
<p>The two fences begin with <code>```rust title="..."</code> and
<code>```rust runnable playgroundLink=false title="..."</code> respectively. Leave out
<code>playgroundLink=false</code> when you want the external Playground fallback. Add
<code>showLineNumbers=10</code> to a read-only block to count from 10, or <code>showLineNumbers=false</code> to
drop the numbers. Running the live example sends its edited source to the official Rust
Playground. To change highlighting and numbering for the whole blog, see <code>code</code> in
<code>openblog.json</code>.</p>
<h2 id="check-your-understanding">Check your understanding<a class="ob-heading-anchor" href="https://open-blog-jtc.netlify.app/posts/writing-a-post/#check-your-understanding" aria-label="Link to this section">#</a></h2>
<section class="ob-knowledge-check" aria-label="Knowledge check">
<div class="ob-quiz">
<p class="ob-quiz-prompt"><strong>What happens when a post is dated in the future?</strong></p>
<ol class="ob-quiz-choices" type="A">
<li>It is published immediately with a future date</li>
<li>It stays hidden until a build runs after the scheduled time</li>
<li>It is automatically saved as a draft</li>
</ol>
<div class="ob-quiz-answer">
<p>Answer: B. It stays hidden until a build runs after the scheduled time</p>
<p>A future-dated post becomes public in the first build run after its scheduled time.</p>
</div>
</div>
</section>
<h2 id="images">Images<a class="ob-heading-anchor" href="https://open-blog-jtc.netlify.app/posts/writing-a-post/#images" aria-label="Link to this section">#</a></h2>
<p>Put files in <code>static/</code>; they are copied to the site root. <code>static/images/photo.png</code> is
<code>/images/photo.png</code>:</p>
<pre><code class="language-markdown">![A short description](/images/photo.png)
</code></pre>
<p>The admin editor uploads and inserts images for you, including by drag and drop or paste.</p>
<p>Next: <a href="https://open-blog-jtc.netlify.app/posts/tags-and-series/">Tags and series</a>.</p>
<div class="footnote-definition" id="1"><sup class="footnote-definition-label">1</sup>
<p>Footnotes render at the end of the post.</p>
</div>
<p class="ob-participation"><a href="https://open-blog-jtc.netlify.app/posts/writing-a-post/#ob-discussion">Join the discussion on the original article</a>.</p>
]]></content:encoded>
</item>
<item>
<title>Welcome to your blog</title>
<link>https://open-blog-jtc.netlify.app/posts/welcome-to-your-blog/</link>
<guid isPermaLink="true">https://open-blog-jtc.netlify.app/posts/welcome-to-your-blog/</guid>
<pubDate>Mon, 05 Jan 2026 00:00:00 GMT</pubDate>
<dc:creator>open.blog</dc:creator>
<category>meta</category>
<description>This is the first post on a fresh open.blog. Edit it, or delete it, to make the blog yours.</description>
<content:encoded><![CDATA[<p>You are looking at <code>content/posts/2026-01-05-welcome-to-your-blog.md</code>. Everything on this
site comes from Markdown files like it. There is no database to set up and nothing to
export later: your posts are plain text in a folder you own.</p>
<h2 id="three-ways-to-write">Three ways to write<a class="ob-heading-anchor" href="https://open-blog-jtc.netlify.app/posts/welcome-to-your-blog/#three-ways-to-write" aria-label="Link to this section">#</a></h2>
<ol>
<li><strong>A text editor.</strong> Open the file, change it, save. <code>openblog serve</code> rebuilds the site
while it runs.</li>
<li><strong>The admin editor.</strong> Run <code>openblog user add you</code>, then <code>openblog serve --admin</code> and
open <code>/admin</code>. It edits these same files, with a live preview.</li>
<li><strong>The command line.</strong> <code>openblog new "A post title"</code> creates a file with today's date.</li>
</ol>
<h2 id="what-a-post-needs">What a post needs<a class="ob-heading-anchor" href="https://open-blog-jtc.netlify.app/posts/welcome-to-your-blog/#what-a-post-needs" aria-label="Link to this section">#</a></h2>
<p>The block between the <code>---</code> lines at the top is the front matter. Only <code>date</code> is required,
plus a <code>title</code> unless the body starts with a <code>#</code> heading. <code>tags</code>, <code>description</code>, <code>series</code>, <code>cover</code>, <code>draft</code>, and <code>theme</code> are optional;
the <a href="https://open-blog-jtc.netlify.app/series/getting-started/">Getting started</a> series walks through them.</p>
<h2 id="make-it-yours">Make it yours<a class="ob-heading-anchor" href="https://open-blog-jtc.netlify.app/posts/welcome-to-your-blog/#make-it-yours" aria-label="Link to this section">#</a></h2>
<ul>
<li>Set the title, description, author, and address in <code>openblog.json</code>.</li>
<li>Replace this post, or keep it as a reminder of how the pieces fit.</li>
<li>Pick a theme in <code>openblog.json</code>, or write one in <code>themes/</code>.</li>
</ul>
<p class="ob-participation"><a href="https://open-blog-jtc.netlify.app/posts/welcome-to-your-blog/#ob-discussion">Join the discussion on the original article</a>.</p>
]]></content:encoded>
</item>
</channel>
</rss>
