{
  "authors": [
    {
      "name": "open.blog",
      "url": "https://github.com/journey-to-code-org/open.blog"
    }
  ],
  "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.",
  "feed_url": "https://open-blog-jtc.netlify.app/feed.json",
  "home_page_url": "https://open-blog-jtc.netlify.app/",
  "items": [
    {
      "content_html": "<p>open.blog keeps authored source readable before it adds any execution. Try changing this greeting;\nwithout JavaScript, it is still an ordinary code block.</p>\n<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>\n<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() {\n    let traveler = &quot;Mira&quot;;\n    println!(&quot;Welcome to the lantern gate, {traveler}!&quot;);\n}\n</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>\n<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>\n<p>Web lessons stay in a dependency-free, opaque-origin preview:</p>\n<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;\n</code></pre><p class=\"ob-web-sandbox-label\">CSS</p><pre><code class=\"language-css\">button { padding: 0.75rem 1rem; color: rebeccapurple; }\n</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;; };\n</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>\n<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>\n<p>The repository example intentionally does not configure an external runner. This Python fence\ntherefore stays static even though it opts into <code>runnable</code>; a site owner must explicitly allow\nPython and deploy an isolated gateway first.</p>\n<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\"\nprint(f\"Welcome, {name}!\")\n</code></pre></figure>\n<p>That fail-closed behavior lets an author keep portable lesson source without silently turning the\nblog or Admin server into a code-execution service.</p>\n<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>\n",
      "content_text": "Executable code lessons, with a safe fallback\nCanonical: https://open-blog-jtc.netlify.app/posts/executable-code-lessons/\nopen.blog keeps authored source readable before it adds any execution. Try changing this greeting;\nwithout JavaScript, it is still an ordinary code block.\nRust works by default\nRust · edit and run\nfn main() {\nlet traveler = \"Mira\";\nprintln!(\"Welcome to the lantern gate, {traveler}!\");\n}\nOpen in Rust Playground (https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&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).\nRun and edit this example on the canonical article (https://open-blog-jtc.netlify.app/posts/executable-code-lessons/).\nWeb lessons stay local\nWeb lessons stay in a dependency-free, opaque-origin preview:\nHTML\n<button id=\"gate\">Reveal the gate</button>\nCSS\nbutton { padding: 0.75rem 1rem; color: rebeccapurple; }\nJavaScript\ndocument.querySelector(\"#gate\").onclick = (event) => { event.currentTarget.textContent = \"The gate opens\"; };\nWeb · reveal the gate on the canonical article (https://open-blog-jtc.netlify.app/posts/executable-code-lessons/).\nConfigured languages fail closed\nThe repository example intentionally does not configure an external runner. This Python fence\ntherefore stays static even though it opts into runnable; a site owner must explicitly allow\nPython and deploy an isolated gateway first.\nPython · static until enabled\nname = input().strip() or \"traveler\"\nprint(f\"Welcome, {name}!\")\nRun and edit this example on the canonical article (https://open-blog-jtc.netlify.app/posts/executable-code-lessons/).\nThat fail-closed behavior lets an author keep portable lesson source without silently turning the\nblog or Admin server into a code-execution service.\nPortable fallback: The source code and canonical run/edit link are preserved; eligible Rust examples also link to the external Playground. Review: Review the preserved source and keep the canonical link for editing or execution.\nPortable fallback: The HTML, CSS, and JavaScript sources are preserved; the live preview remains on the canonical article. Review: Review the preserved source and keep the canonical link for editing or execution.\nPortable fallback: The source code and canonical run/edit link are preserved; eligible Rust examples also link to the external Playground. Review: Review the preserved source and keep the canonical link for editing or execution.\nJoin the discussion on the canonical article (https://open-blog-jtc.netlify.app/posts/executable-code-lessons/#ob-discussion)",
      "date_published": "2026-10-24T00:00:00Z",
      "id": "https://open-blog-jtc.netlify.app/posts/executable-code-lessons/",
      "summary": "Rust and browser lessons work out of the box; configured languages fail closed until a separate runner is enabled.",
      "tags": [
        "tutorial",
        "rust",
        "web"
      ],
      "title": "Executable code lessons, with a safe fallback",
      "url": "https://open-blog-jtc.netlify.app/posts/executable-code-lessons/"
    },
    {
      "content_html": "<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>\n<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>\n<aside class=\"ob-callout ob-callout-note\" role=\"note\"><p class=\"ob-callout-title\"><strong>Note</strong></p>\n<p>This is a fictional product example, not an actual Lantern Gate Studios release or production\ncredit. It is intended to be replaced with the studio's real words and media.</p>\n</aside>\n<p>Seven travelers arrive at a sealed mountain gate as an old ward begins to fail. This companion page\nkeeps the episode, production context, and accessible transcript in creator-owned Markdown.</p>\n<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>\n<ol class=\"ob-chapters\" aria-label=\"Video chapters\">\n<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>\n<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>\n<li><a href=\"https://www.youtube.com/watch?v=Zha1endor01&amp;t=96s\"><time datetime=\"PT96S\">01:36</time></a> The gate answers</li>\n<li><a href=\"https://www.youtube.com/watch?v=Zha1endor01&amp;t=148s\"><time datetime=\"PT148S\">02:28</time></a> Beyond the threshold</li>\n</ol>\n<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>\n<ul>\n<li><input disabled=\"\" type=\"checkbox\" checked=\"\"/>\nStory beat and continuity review</li>\n<li><input disabled=\"\" type=\"checkbox\" checked=\"\"/>\nShot list and animatic</li>\n<li><input disabled=\"\" type=\"checkbox\" checked=\"\"/>\nVoice and sound pass</li>\n<li><input disabled=\"\" type=\"checkbox\"/>\nFinal color and accessibility review</li>\n<li><input disabled=\"\" type=\"checkbox\"/>\nRelease copy and scheduled publication</li>\n</ul>\n<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>\n<p>The opening uses a wide silhouette before moving to individual reaction shots. The gate remains the\nvisual anchor, while ember light distinguishes forbidden magic from ordinary torchlight.</p>\n<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>\n<p><strong>Narrator:</strong> The mountain had no door on any map, but every road bent toward it.</p>\n<p><strong>Mara:</strong> Nobody touches the seal until we know who lit those runes.</p>\n<p><strong>Narrator:</strong> From the other side came a sound like a great chain falling through the dark.</p>\n<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>\n",
      "content_text": "Zhalendor — The Gate of Embers\nCanonical: https://open-blog-jtc.netlify.app/posts/zhalendor-gate-of-embers/\nNote:\nThis is a fictional product example, not an actual Lantern Gate Studios release or production\ncredit. It is intended to be replaced with the studio's real words and media.\nSeven travelers arrive at a sealed mountain gate as an old ward begins to fail. This companion page\nkeeps the episode, production context, and accessible transcript in creator-owned Markdown.\nChapters\n00:00 The road beneath the mountain\n00:42 A warning in the ash\n01:36 The gate answers\n02:28 Beyond the threshold\nProduction log\nStory beat and continuity review\nShot list and animatic\nVoice and sound pass\nFinal color and accessibility review\nRelease copy and scheduled publication\nShot notes\nThe opening uses a wide silhouette before moving to individual reaction shots. The gate remains the\nvisual anchor, while ember light distinguishes forbidden magic from ordinary torchlight.\nTranscript\nNarrator: The mountain had no door on any map, but every road bent toward it.\nMara: Nobody touches the seal until we know who lit those runes.\nNarrator: From the other side came a sound like a great chain falling through the dark.\nVideo details\nEpisode: Season 1, episode 1\nProduction status: editing\nProduction credits: Story and direction by the Lantern Gate team; animation and edit by the episode crew\nVideo: Zhalendor — The Gate of Embers (https://youtu.be/Zha1endor01)\nRead the discussion on the canonical article (https://open-blog-jtc.netlify.app/posts/zhalendor-gate-of-embers/#ob-discussion)",
      "date_published": "2026-10-24T00:00:00Z",
      "id": "https://open-blog-jtc.netlify.app/posts/zhalendor-gate-of-embers/",
      "summary": "A fictional Lantern Gate Studios episode page demonstrating production status, credits, chapters, a transcript, and AI-assistance disclosure.",
      "tags": [
        "animation",
        "fantasy",
        "behind-the-scenes"
      ],
      "title": "Zhalendor — The Gate of Embers",
      "url": "https://open-blog-jtc.netlify.app/posts/zhalendor-gate-of-embers/"
    },
    {
      "content_html": "<p>The rain stopped shortly before sunrise, but the woods kept dripping for most of the\nmorning. Water moved through every shallow channel beside the trail, and the first rocky\nclimb was slick enough to slow the pace.</p>\n<aside class=\"ob-callout ob-callout-note\" role=\"note\"><p class=\"ob-callout-title\"><strong>Note</strong></p>\n<p>This is a fictional but realistic working example. Its location is deliberately\ngeneralized, and its route drawing contains normalized illustration points—not latitude\nand longitude.</p>\n</aside>\n<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>\n<p>The lower trail crossed mixed hardwood forest before turning uphill through hemlock and\nwhite pine. At roughly the halfway point, the path reached an exposed ledge where wind had\nalready dried the rock. Low cloud hid the farther hills, so I turned around at the next\njunction instead of completing the longer loop.</p>\n<p>The approximate route above is enough to show the shape and effort of the outing without\npublishing a trailhead, campsite, or observation coordinate. For a real post, import a GPX\nfile in <strong>Field Review</strong> and choose the privacy mode before saving.</p>\n<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>\n<ul>\n<li>Several red-backed salamanders were active beneath already-loose bark beside the path.\nI left the bark in place and did not record a precise location.</li>\n<li>Club moss was bright green across the shaded slope, while the exposed ridge vegetation\nwas already dormant.</li>\n<li>Fresh boot widening was visible around two muddy sections. Staying in the center of the\ntread kept the disturbed area from spreading farther into the understory.</li>\n<li>A small drainage crossing was carrying clear water with no visible sediment plume.</li>\n</ul>\n<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>\n<p>The first kilometer was broad and gently graded. Beyond the stream crossing, roots, wet\nslabs, and two short step-ups made the route unsuitable for wheels and potentially difficult\nfor hikers with limited balance. Cell service was intermittent below the ridge. There was\nno reliable water source after the crossing.</p>\n<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>\n<p>One fist-sized branch had fallen across the drainage outlet near the lower switchback. I\nmoved only the loose branch, leaving embedded rocks and the channel itself untouched. The\nlarger muddy section would benefit from assessment by the trail steward rather than an\ninformal reroute.</p>\n<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>\n<ul>\n<li>Trekking poles for the wet descent</li>\n<li>A small towel for camera gear</li>\n<li>Offline trail information downloaded before leaving</li>\n<li>A few extra minutes to document the widening tread for the local steward</li>\n</ul>\n<p>Field journals work best when they record what was actually observed, distinguish estimates\nfrom measurements, and reveal no more location detail than the story needs.</p>\n<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>\n",
      "content_text": "A wet morning on the ridge\nCanonical: https://open-blog-jtc.netlify.app/posts/a-wet-morning-on-the-ridge/\nThe rain stopped shortly before sunrise, but the woods kept dripping for most of the\nmorning. Water moved through every shallow channel beside the trail, and the first rocky\nclimb was slick enough to slow the pace.\nNote:\nThis is a fictional but realistic working example. Its location is deliberately\ngeneralized, and its route drawing contains normalized illustration points—not latitude\nand longitude.\nRoute notes\nThe lower trail crossed mixed hardwood forest before turning uphill through hemlock and\nwhite pine. At roughly the halfway point, the path reached an exposed ledge where wind had\nalready dried the rock. Low cloud hid the farther hills, so I turned around at the next\njunction instead of completing the longer loop.\nThe approximate route above is enough to show the shape and effort of the outing without\npublishing a trailhead, campsite, or observation coordinate. For a real post, import a GPX\nfile in Field Review and choose the privacy mode before saving.\nField observations\nSeveral red-backed salamanders were active beneath already-loose bark beside the path.\nI left the bark in place and did not record a precise location.\nClub moss was bright green across the shaded slope, while the exposed ridge vegetation\nwas already dormant.\nFresh boot widening was visible around two muddy sections. Staying in the center of the\ntread kept the disturbed area from spreading farther into the understory.\nA small drainage crossing was carrying clear water with no visible sediment plume.\nTrail and access conditions\nThe first kilometer was broad and gently graded. Beyond the stream crossing, roots, wet\nslabs, and two short step-ups made the route unsuitable for wheels and potentially difficult\nfor hikers with limited balance. Cell service was intermittent below the ridge. There was\nno reliable water source after the crossing.\nStewardship note\nOne fist-sized branch had fallen across the drainage outlet near the lower switchback. I\nmoved only the loose branch, leaving embedded rocks and the channel itself untouched. The\nlarger muddy section would benefit from assessment by the trail steward rather than an\ninformal reroute.\nWhat I would bring next time\nTrekking poles for the wet descent\nA small towel for camera gear\nOffline trail information downloaded before leaving\nA few extra minutes to document the widening tread for the local steward\nField journals work best when they record what was actually observed, distinguish estimates\nfrom measurements, and reveal no more location detail than the story needs.\nJoin the discussion on the canonical article (https://open-blog-jtc.netlify.app/posts/a-wet-morning-on-the-ridge/#ob-discussion)",
      "date_published": "2026-10-23T00:00:00Z",
      "id": "https://open-blog-jtc.netlify.app/posts/a-wet-morning-on-the-ridge/",
      "image": "https://open-blog-jtc.netlify.app/images/misty-ridge-field-note.jpg",
      "summary": "A working field-journal example with trail conditions, observations, an approximate route, and practical stewardship notes.",
      "tags": [
        "hiking",
        "field-notes",
        "stewardship"
      ],
      "title": "A wet morning on the ridge",
      "url": "https://open-blog-jtc.netlify.app/posts/a-wet-morning-on-the-ridge/"
    },
    {
      "authors": [
        {
          "name": "Example Author"
        }
      ],
      "content_html": "<aside class=\"ob-contributions\" aria-labelledby=\"ob-contributions-title\">\n<h2 id=\"ob-contributions-title\" class=\"ob-contributions-title\">Contributions</h2>\n<ul>\n<li><div><span class=\"ob-contributor-name\">Example Author</span><span class=\"ob-contributor-roles\">Author, Conceptualization, Writing – original draft</span></div></li>\n<li><div><span class=\"ob-contributor-name\">Example Editor</span><span class=\"ob-contributor-roles\">Editor, Writing – review &amp; editing</span></div></li>\n</ul>\n</aside>\n<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>\n<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>\n<p>This working example shows how a portable Markdown article can publish research-oriented\nmetadata and credit more than one person without putting identity data in front matter. The\npost selects the <code>research</code> profile, while an adjacent JSON sidecar supplies ordered authorship\nand controlled contributor roles.</p>\n<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>\n<p>Three files make the demonstration work:</p>\n<ol>\n<li><code>openblog.json</code> registers the reusable <code>example-author</code> and <code>example-editor</code> identities.</li>\n<li>This Markdown file contains the article, license, Abstract, and References sections.</li>\n<li><code>2026-02-16-research-and-contributor-credits.credits.json</code> connects those identities to\nthis work with Crossref and CRediT roles.</li>\n</ol>\n<p>The identities are deliberately synthetic and their ORCID fields are empty. Replace them with\nreal people and add only identifiers those people actually control. Manually entered ORCID iDs\nremain visibly labeled as unauthenticated.</p>\n<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>\n<p>Open this post in Admin Studio to see the same data from an author's point of view:</p>\n<ul>\n<li><strong>Settings → Credit contributors and roles</strong> preserves credit order and exposes controlled\nroles.</li>\n<li><strong>Evidence</strong> reports the research structure and bounded reference links below.</li>\n<li><strong>Site preview</strong> renders the production byline, work details, and Contributions panel.</li>\n<li><strong>Social</strong> uses the same publishing-engine metadata as the generated page.</li>\n</ul>\n<p>After <code>openblog build</code>, inspect this page, <code>rss.xml</code>, <code>feed.json</code>, and the page's JSON-LD.\nOnly the Crossref author appears in author-only metadata; both people and all their roles remain\nvisible in the Contributions panel.</p>\n<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>\n<ol>\n<li><a href=\"https://credit.niso.org/\">CRediT role taxonomy</a></li>\n<li><a href=\"https://www.crossref.org/documentation/schema-library/markup-guide-metadata-segments/contributors/\">Crossref contributor guidance</a></li>\n</ol>\n<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>\n",
      "content_text": "Research posts and contributor credits\nCanonical: https://open-blog-jtc.netlify.app/posts/research-and-contributor-credits/\nAbstract\nThis working example shows how a portable Markdown article can publish research-oriented\nmetadata and credit more than one person without putting identity data in front matter. The\npost selects the research profile, while an adjacent JSON sidecar supplies ordered authorship\nand controlled contributor roles.\nFollow the source files\nThree files make the demonstration work:\nopenblog.json registers the reusable example-author and example-editor identities.\nThis Markdown file contains the article, license, Abstract, and References sections.\n2026-02-16-research-and-contributor-credits.credits.json connects those identities to\nthis work with Crossref and CRediT roles.\nThe identities are deliberately synthetic and their ORCID fields are empty. Replace them with\nreal people and add only identifiers those people actually control. Manually entered ORCID iDs\nremain visibly labeled as unauthenticated.\nWhat to inspect\nOpen this post in Admin Studio to see the same data from an author's point of view:\nSettings → Credit contributors and roles preserves credit order and exposes controlled\nroles.\nEvidence reports the research structure and bounded reference links below.\nSite preview renders the production byline, work details, and Contributions panel.\nSocial uses the same publishing-engine metadata as the generated page.\nAfter openblog build, inspect this page, rss.xml, feed.json, and the page's JSON-LD.\nOnly the Crossref author appears in author-only metadata; both people and all their roles remain\nvisible in the Contributions panel.\nReferences\nCRediT role taxonomy (https://credit.niso.org/)\nCrossref contributor guidance (https://www.crossref.org/documentation/schema-library/markup-guide-metadata-segments/contributors/)\nContributions\nExample Author — Author, Conceptualization, Writing – original draft\nExample Editor — Editor, Writing – review & editing\nWork details\nLicense: https://creativecommons.org/licenses/by/4.0/\nJoin the discussion on the canonical article (https://open-blog-jtc.netlify.app/posts/research-and-contributor-credits/#ob-discussion)",
      "date_published": "2026-02-16T00:00:00Z",
      "id": "https://open-blog-jtc.netlify.app/posts/research-and-contributor-credits/",
      "summary": "A working example of research metadata, ordered authorship, contributor roles, references, and the Admin Studio workflow.",
      "tags": [
        "research",
        "guide",
        "collaboration"
      ],
      "title": "Research posts and contributor credits",
      "url": "https://open-blog-jtc.netlify.app/posts/research-and-contributor-credits/"
    },
    {
      "content_html": "<p>Publishing in more than one community can help readers find your work, but your blog\nshould remain the source of truth. The dependable sequence is:</p>\n<ol>\n<li>publish the article on your open.blog site;</li>\n<li>make sure its final URL is live;</li>\n<li>create drafts on the other platforms;</li>\n<li>set each copy's canonical URL back to the open.blog article;</li>\n<li>review the formatting, then publish the copies.</li>\n</ol>\n<p>The canonical URL tells search engines which copy is the original. Deploying that URL\nfirst also prevents every destination from pointing at a page that does not exist yet.</p>\n<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>\n<p>Every open.blog site can expose full-content RSS at <code>/rss.xml</code> and JSON Feed at\n<code>/feed.json</code>. Enable <code>feeds.rss</code>, <code>feeds.json</code>, and <code>feeds.fullContent</code> in\n<code>openblog.json</code>. A feed automation service can then watch either URL and create a draft\nwhen a new post appears.</p>\n<p>Before connecting one, confirm that its destination action can:</p>\n<ul>\n<li>create a draft instead of publishing immediately;</li>\n<li>set the original article URL as canonical;</li>\n<li>update the same remote article rather than create a duplicate.</li>\n</ul>\n<p>If it cannot do those things, use the destination's API or import flow instead.</p>\n<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>\n<ul>\n<li><strong>Hashnode:</strong> its official GitHub Action can publish repository Markdown and supports\ndrafts, dry runs, and canonical URLs. API publishing now requires a Hashnode Pro\npublication.</li>\n<li><strong>DEV Community:</strong> its API accepts Markdown, supports drafts, and has a\n<code>canonical_url</code> field. Save the returned article ID so future runs update the same\npost.</li>\n<li><strong>Medium:</strong> use <strong>Import a story</strong> after the original is live. Medium does not accept\nnew API integrations; its importer adds the original URL as canonical automatically.</li>\n<li><strong>Ghost:</strong> its Admin API supports drafts and custom canonical URLs. Keep the Admin API\nkey on a trusted server or in CI, never in browser JavaScript.</li>\n<li><strong>WordPress:</strong> its REST API supports drafts, but core WordPress has no portable field\nfor an external canonical. Only syndicate automatically if your particular SEO plugin\nor site configuration exposes and verifies one.</li>\n</ul>\n<p>The repository's\n<a href=\"https://github.com/journey-to-code-org/open.blog/blob/main/docs/cross-posting.md\">complete cross-posting guide</a>\nwalks through credentials, API requests, CI safety, updating instead of duplicating, and\nthe official documentation for each platform. It also includes a complete GitHub\nActions template that waits for deployment, verifies the canonical URL, and creates or\nupdates a DEV draft from the deployed JSON Feed.</p>\n<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>\n<p>Store tokens as encrypted CI secrets. Never put one in Markdown front matter, the\ngenerated site, or code that runs in a reader's browser. Start every integration in\ndraft mode and test it with one disposable article.</p>\n<p>Once that works, automation can handle the repetitive copying while you keep the final\nreview. Your Markdown stays authoritative, every public copy points home, and a failure\non one community does not prevent the original article from reaching your readers.</p>\n<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>\n",
      "content_text": "Safely cross-posting your blog\nCanonical: https://open-blog-jtc.netlify.app/posts/automated-cross-posting/\nPublishing in more than one community can help readers find your work, but your blog\nshould remain the source of truth. The dependable sequence is:\npublish the article on your open.blog site;\nmake sure its final URL is live;\ncreate drafts on the other platforms;\nset each copy's canonical URL back to the open.blog article;\nreview the formatting, then publish the copies.\nThe canonical URL tells search engines which copy is the original. Deploying that URL\nfirst also prevents every destination from pointing at a page that does not exist yet.\nStart with the feeds\nEvery open.blog site can expose full-content RSS at /rss.xml and JSON Feed at\n/feed.json. Enable feeds.rss, feeds.json, and feeds.fullContent in\nopenblog.json. A feed automation service can then watch either URL and create a draft\nwhen a new post appears.\nBefore connecting one, confirm that its destination action can:\ncreate a draft instead of publishing immediately;\nset the original article URL as canonical;\nupdate the same remote article rather than create a duplicate.\nIf it cannot do those things, use the destination's API or import flow instead.\nPick the right setup for each platform\nHashnode: its official GitHub Action can publish repository Markdown and supports\ndrafts, dry runs, and canonical URLs. API publishing now requires a Hashnode Pro\npublication.\nDEV Community: its API accepts Markdown, supports drafts, and has a\ncanonical_url field. Save the returned article ID so future runs update the same\npost.\nMedium: use Import a story after the original is live. Medium does not accept\nnew API integrations; its importer adds the original URL as canonical automatically.\nGhost: its Admin API supports drafts and custom canonical URLs. Keep the Admin API\nkey on a trusted server or in CI, never in browser JavaScript.\nWordPress: its REST API supports drafts, but core WordPress has no portable field\nfor an external canonical. Only syndicate automatically if your particular SEO plugin\nor site configuration exposes and verifies one.\nThe repository's\ncomplete cross-posting guide (https://github.com/journey-to-code-org/open.blog/blob/main/docs/cross-posting.md)\nwalks through credentials, API requests, CI safety, updating instead of duplicating, and\nthe official documentation for each platform. It also includes a complete GitHub\nActions template that waits for deployment, verifies the canonical URL, and creates or\nupdates a DEV draft from the deployed JSON Feed.\nKeep publishing credentials private\nStore tokens as encrypted CI secrets. Never put one in Markdown front matter, the\ngenerated site, or code that runs in a reader's browser. Start every integration in\ndraft mode and test it with one disposable article.\nOnce that works, automation can handle the repetitive copying while you keep the final\nreview. Your Markdown stays authoritative, every public copy points home, and a failure\non one community does not prevent the original article from reaching your readers.\nJoin the discussion on the canonical article (https://open-blog-jtc.netlify.app/posts/automated-cross-posting/#ob-discussion)",
      "date_published": "2026-02-09T00:00:00Z",
      "id": "https://open-blog-jtc.netlify.app/posts/automated-cross-posting/",
      "summary": "Publish here first, then send reviewable, canonical copies to DEV, Hashnode, Medium, Ghost, or WordPress.",
      "tags": [
        "guide"
      ],
      "title": "Safely cross-posting your blog",
      "url": "https://open-blog-jtc.netlify.app/posts/automated-cross-posting/"
    },
    {
      "content_html": "<section class=\"ob-recipe-card\" aria-label=\"Recipe summary\">\n<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>\n</section>\n<p>open.blog is not only for code. Add <code>profile: recipe</code> to a post's front matter, put the\ningredients in a list under an <code>## Ingredients</code> heading and the steps in a list under a\n<code>## Steps</code> heading, and the post becomes a recipe:</p>\n<ul>\n<li>A summary card with the times and servings, and a \"Jump to recipe\" link.</li>\n<li>Buttons that scale the amount at the start of each ingredient to more or fewer servings.</li>\n<li>Checkboxes to tick off ingredients and steps (remembered on the reader's device).</li>\n<li>Timers: any time in a step, like \"10 minutes\", starts a countdown when tapped.</li>\n<li>Cook mode keeps the screen awake, and \"Print recipe\" prints just the recipe.</li>\n<li>Search engines get schema.org recipe data; with a photo, the post can appear as a recipe result.</li>\n</ul>\n<p>Start a new one with <code>openblog new \"Lemon garlic pasta\" --recipe</code>. This post is a working\nexample; try the buttons above.</p>\n<aside class=\"ob-callout ob-callout-tip\" role=\"note\"><p class=\"ob-callout-title\"><strong>Tip</strong></p>\n<p>Save a cup of the pasta water before you drain it. Its starch makes the sauce glossy.</p>\n</aside>\n<section class=\"ob-recipe-part ob-recipe-ingredients\">\n<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>\n<ul class=\"ob-recipe-list ob-ingredients\">\n<li>400 g spaghetti</li>\n<li>3 tbsp olive oil</li>\n<li>4 cloves garlic, thinly sliced</li>\n<li>1 1/2 lemons, zested and juiced</li>\n<li>1/2 cup grated parmesan, plus more to serve</li>\n<li>1 handful parsley, chopped</li>\n<li>Salt and black pepper, to taste</li>\n</ul>\n</section>\n<section class=\"ob-recipe-part ob-recipe-steps\">\n<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>\n<ol class=\"ob-recipe-list ob-steps\">\n<li>Bring a large pot of salted water to the boil and cook the spaghetti for 9 minutes.</li>\n<li>Meanwhile, warm the olive oil in a wide pan over low heat and cook the garlic for\n2-3 minutes, until soft but not brown.</li>\n<li>Save a cup of the pasta water, then drain the spaghetti and add it to the pan.</li>\n<li>Add the lemon zest and juice, the parmesan, and a splash of pasta water. Toss for\n1 minute, until glossy, adding more water if it looks dry.</li>\n<li>Season, scatter over the parsley, and serve with more parmesan.</li>\n</ol>\n</section>\n<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>\n<p>The front matter for this post:</p>\n<pre><code class=\"language-yaml\">profile: recipe\nservings: 4\nprep: 10 min\ncook: 15 min\ncuisine: Italian\ncourse: Dinner\n</code></pre>\n<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>\nis shown as written. Use <code>makes: 12 cookies</code> to say what a recipe makes, alongside\n<code>servings</code> if readers should be able to scale it.</p>\n<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>\n",
      "content_text": "Recipes, too: lemon garlic pasta\nCanonical: https://open-blog-jtc.netlify.app/posts/recipes-for-cooks/\nopen.blog is not only for code. Add profile: recipe to a post's front matter, put the\ningredients in a list under an ## Ingredients heading and the steps in a list under a\n## Steps heading, and the post becomes a recipe:\nA summary card with the times and servings, and a \"Jump to recipe\" link.\nButtons that scale the amount at the start of each ingredient to more or fewer servings.\nCheckboxes to tick off ingredients and steps (remembered on the reader's device).\nTimers: any time in a step, like \"10 minutes\", starts a countdown when tapped.\nCook mode keeps the screen awake, and \"Print recipe\" prints just the recipe.\nSearch engines get schema.org recipe data; with a photo, the post can appear as a recipe result.\nStart a new one with openblog new \"Lemon garlic pasta\" --recipe. This post is a working\nexample; try the buttons above.\nTip:\nSave a cup of the pasta water before you drain it. Its starch makes the sauce glossy.\nIngredients\n400 g spaghetti\n3 tbsp olive oil\n4 cloves garlic, thinly sliced\n1 1/2 lemons, zested and juiced\n1/2 cup grated parmesan, plus more to serve\n1 handful parsley, chopped\nSalt and black pepper, to taste\nSteps\nBring a large pot of salted water to the boil and cook the spaghetti for 9 minutes.\nMeanwhile, warm the olive oil in a wide pan over low heat and cook the garlic for\n2-3 minutes, until soft but not brown.\nSave a cup of the pasta water, then drain the spaghetti and add it to the pan.\nAdd the lemon zest and juice, the parmesan, and a splash of pasta water. Toss for\n1 minute, until glossy, adding more water if it looks dry.\nSeason, scatter over the parsley, and serve with more parmesan.\nNotes\nThe front matter for this post:\nprofile: recipe\nservings: 4\nprep: 10 min\ncook: 15 min\ncuisine: Italian\ncourse: Dinner\nTimes can be written as 15 min, 1 hr 30 min, or 1:30; something like overnight\nis shown as written. Use makes: 12 cookies to say what a recipe makes, alongside\nservings if readers should be able to scale it.\nRecipe details\nPrep: 10 min\nCook: 15 min\nTotal: 25 min\nServes: 4\nCuisine: Italian\nCourse: Dinner\nJoin the discussion on the canonical article (https://open-blog-jtc.netlify.app/posts/recipes-for-cooks/#ob-discussion)",
      "date_published": "2026-02-02T00:00:00Z",
      "id": "https://open-blog-jtc.netlify.app/posts/recipes-for-cooks/",
      "summary": "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.",
      "tags": [
        "recipe",
        "guide"
      ],
      "title": "Recipes, too: lemon garlic pasta",
      "url": "https://open-blog-jtc.netlify.app/posts/recipes-for-cooks/"
    },
    {
      "content_html": "<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>\n<pre><code class=\"language-sh\">openblog build\n</code></pre>\n<p>writes a complete static site to <code>dist/</code>: pages, RSS and JSON feeds, a sitemap, a search\nindex, and the assets. Upload that folder to any static host, or run <code>openblog serve</code> to\nhost it yourself.</p>\n<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>\n<p><code>draft: true</code> keeps a post out of every build and feed. <code>openblog serve --drafts</code> previews\ndrafts locally. The admin editor shows drafts with their own badge.</p>\n<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>\n<p>Give a post a date in the future and it is <em>scheduled</em>:</p>\n<pre><code class=\"language-yaml\">date: 2026-12-25T09:00:00Z\n</code></pre>\n<p>Scheduled posts stay out of the pages, feeds, sitemap, and search index. When the time\ncomes, <code>openblog serve</code> rebuilds by itself. On a static host, any <code>openblog build</code> after\nthat time publishes it, so a daily build (a cron job or a scheduled workflow) is enough.</p>\n<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>\n<p>For editing from a browser, including on the server that hosts the blog:</p>\n<pre><code class=\"language-sh\">openblog user add you\nopenblog serve --admin\n</code></pre>\n<p>Then open <code>/admin</code>. It writes the same Markdown files, so you can mix both ways of\nworking. <code>docs/admin.md</code> covers running it safely on the public internet.</p>\n<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>\n<p><code>/rss.xml</code> carries the full post HTML and <code>/feed.json</code> is JSON Feed 1.1. Most newsletter\nand cross-posting tools accept either. If you republish a post elsewhere, set the copy's\ncanonical URL to its address here; for a post that was first published elsewhere, set\n<code>canonical:</code> in its front matter.</p>\n<p>Continue with <a href=\"https://open-blog-jtc.netlify.app/posts/automated-cross-posting/\">Safely cross-posting your blog</a> for a\nreview-first workflow covering Hashnode, DEV, Medium, Ghost, and WordPress.</p>\n<p>That is the whole workflow. Delete this series when your own posts arrive, or keep it as\na reference.</p>\n<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>\n",
      "content_text": "Publishing and scheduling\nCanonical: https://open-blog-jtc.netlify.app/posts/publishing-and-scheduling/\nBuild and host\nopenblog build\nwrites a complete static site to dist/: pages, RSS and JSON feeds, a sitemap, a search\nindex, and the assets. Upload that folder to any static host, or run openblog serve to\nhost it yourself.\nDrafts\ndraft: true keeps a post out of every build and feed. openblog serve --drafts previews\ndrafts locally. The admin editor shows drafts with their own badge.\nScheduling\nGive a post a date in the future and it is scheduled:\ndate: 2026-12-25T09:00:00Z\nScheduled posts stay out of the pages, feeds, sitemap, and search index. When the time\ncomes, openblog serve rebuilds by itself. On a static host, any openblog build after\nthat time publishes it, so a daily build (a cron job or a scheduled workflow) is enough.\nThe admin editor\nFor editing from a browser, including on the server that hosts the blog:\nopenblog user add you\nopenblog serve --admin\nThen open /admin. It writes the same Markdown files, so you can mix both ways of\nworking. docs/admin.md covers running it safely on the public internet.\nFeeds and cross-posting\n/rss.xml carries the full post HTML and /feed.json is JSON Feed 1.1. Most newsletter\nand cross-posting tools accept either. If you republish a post elsewhere, set the copy's\ncanonical URL to its address here; for a post that was first published elsewhere, set\ncanonical: in its front matter.\nContinue with Safely cross-posting your blog (https://open-blog-jtc.netlify.app/posts/automated-cross-posting/) for a\nreview-first workflow covering Hashnode, DEV, Medium, Ghost, and WordPress.\nThat is the whole workflow. Delete this series when your own posts arrive, or keep it as\na reference.\nJoin the discussion on the canonical article (https://open-blog-jtc.netlify.app/posts/publishing-and-scheduling/#ob-discussion)",
      "date_published": "2026-01-26T00:00:00Z",
      "id": "https://open-blog-jtc.netlify.app/posts/publishing-and-scheduling/",
      "summary": "Build the site, host it anywhere, keep a draft private, and schedule a post for later.",
      "tags": [
        "guide"
      ],
      "title": "Publishing and scheduling",
      "url": "https://open-blog-jtc.netlify.app/posts/publishing-and-scheduling/"
    },
    {
      "content_html": "<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>\n<p>List them in the front matter. Each tag gets a page at <code>/tags/&lt;slug&gt;/</code>, and <code>/tags/</code> lists\nthem all with counts. Tags are matched case-insensitively, so <code>Rust</code> and <code>rust</code> are one tag.</p>\n<pre><code class=\"language-yaml\">tags:\n  - guide\n  - rust\n</code></pre>\n<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>\n<p>A series is a file in <code>content/series/</code>. This one is <code>content/series/getting-started.md</code>:</p>\n<pre><code class=\"language-yaml\">---\nname: Getting started\ndescription: Three short parts ...\ntheme: demo        # every post in the series renders with this theme\norder: 1           # position on the /series/ page\n---\nOptional Markdown shown at the top of the series page.\n</code></pre>\n<p>A post joins a series with <code>series: getting-started</code>. Parts are ordered by <code>seriesOrder</code>,\nor by date when it is missing. The post page then shows \"Part 2 of 3\", previous and next\nlinks, and a list of all parts. If you reference a series that has no file, open.blog\ncreates it from the slug and warns you.</p>\n<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>\n<p>Set <code>theme:</code> on a series and all of its posts switch theme, including this one. A single\npost can override with <code>theme:</code> of its own. The themes available are the folders under\n<code>themes/</code>; run <code>openblog themes</code> to list them. See <code>docs/themes.md</code> for how a theme is\nbuilt from design tokens, and <code>docs/theme-components.md</code> for the heading effect this\nseries is using.</p>\n<p>Next: <a href=\"https://open-blog-jtc.netlify.app/posts/publishing-and-scheduling/\">Publishing and scheduling</a>.</p>\n<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>\n",
      "content_text": "Tags and series\nCanonical: https://open-blog-jtc.netlify.app/posts/tags-and-series/\nTags\nList them in the front matter. Each tag gets a page at /tags/<slug>/, and /tags/ lists\nthem all with counts. Tags are matched case-insensitively, so Rust and rust are one tag.\ntags:\n- guide\n- rust\nSeries\nA series is a file in content/series/. This one is content/series/getting-started.md:\n---\nname: Getting started\ndescription: Three short parts ...\ntheme: demo        # every post in the series renders with this theme\norder: 1           # position on the /series/ page\n---\nOptional Markdown shown at the top of the series page.\nA post joins a series with series: getting-started. Parts are ordered by seriesOrder,\nor by date when it is missing. The post page then shows \"Part 2 of 3\", previous and next\nlinks, and a list of all parts. If you reference a series that has no file, open.blog\ncreates it from the slug and warns you.\nThemes per series\nSet theme: on a series and all of its posts switch theme, including this one. A single\npost can override with theme: of its own. The themes available are the folders under\nthemes/; run openblog themes to list them. See docs/themes.md for how a theme is\nbuilt from design tokens, and docs/theme-components.md for the heading effect this\nseries is using.\nNext: Publishing and scheduling (https://open-blog-jtc.netlify.app/posts/publishing-and-scheduling/).\nJoin the discussion on the canonical article (https://open-blog-jtc.netlify.app/posts/tags-and-series/#ob-discussion)",
      "date_published": "2026-01-19T00:00:00Z",
      "id": "https://open-blog-jtc.netlify.app/posts/tags-and-series/",
      "summary": "Tags group posts by topic. Series put posts in reading order, and each series can have its own theme.",
      "tags": [
        "guide"
      ],
      "title": "Tags and series",
      "url": "https://open-blog-jtc.netlify.app/posts/tags-and-series/"
    },
    {
      "content_html": "<p>A post is a Markdown file in <code>content/posts/</code>. The file name can start with a date\n(<code>2026-01-12-writing-a-post.md</code>); the rest becomes the slug, so this post lives at\n<code>/posts/writing-a-post/</code>. Add <code>slug:</code> to the front matter to choose a different one.</p>\n<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>\n<pre><code class=\"language-yaml\">---\ntitle: Writing a post\nsubtitle: Optional. A one-line subheading shown under the title.\ndate: 2026-01-12           # or a full time: 2026-01-12T09:30:00Z\ntags: [guide, markdown]    # inline lists work too\ndescription: Optional. Used in feeds and search results.\ncover: /images/cover.png   # optional; the first image in the body is the fallback\ndraft: false\n---\n</code></pre>\n<p>Dates without a time are midnight UTC. A post dated in the future is <em>scheduled</em> and stays\nhidden until that moment (part three has the details).</p>\n<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>\n<p>CommonMark plus the GitHub extensions: tables, task lists, footnotes, and strikethrough.\nHeadings get ids and anchor links, so <code>#markdown-that-works</code> links here.</p>\n<table><thead><tr><th>Feature</th><th>Syntax</th></tr></thead><tbody>\n<tr><td>Task list</td><td><code>- [x] done</code></td></tr>\n<tr><td>Footnote</td><td><code>text[^1]</code></td></tr>\n<tr><td>Strikethrough</td><td><code>~~old~~</code></td></tr>\n</tbody></table>\n<ul>\n<li><input disabled=\"\" type=\"checkbox\" checked=\"\"/>\nWrite the post</li>\n<li><input disabled=\"\" type=\"checkbox\"/>\nPublish it</li>\n</ul>\n<p>Callouts draw attention to a note, a tip, or a warning:</p>\n<aside class=\"ob-callout ob-callout-tip\" role=\"note\"><p class=\"ob-callout-title\"><strong>Tip</strong></p>\n<p>Write <code>&gt; [!NOTE]</code>, <code>&gt; [!TIP]</code>, <code>&gt; [!IMPORTANT]</code>, <code>&gt; [!WARNING]</code>, or <code>&gt; [!CAUTION]</code>\non the first line of a quote.</p>\n</aside>\n<p>Regular code blocks are read-only: they keep the original syntax colouring, line numbers,\nhighlighted lines, and copy button. This one demonstrates that decorative presentation:</p>\n<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 {\n    format!(\"Hello, {name}!\")\n}\n</code></pre></figure>\n<p>Add <code>runnable</code> only when readers should be able to edit and execute a self-contained Rust\nexample. A runnable block deliberately becomes an editor with controls and inline output:</p>\n<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() {\n    let name = &quot;reader&quot;;\n    println!(&quot;Hello, {name}!&quot;);\n}\n</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>\n<p>The two fences begin with <code>```rust title=\"...\"</code> and\n<code>```rust runnable playgroundLink=false title=\"...\"</code> respectively. Leave out\n<code>playgroundLink=false</code> when you want the external Playground fallback. Add\n<code>showLineNumbers=10</code> to a read-only block to count from 10, or <code>showLineNumbers=false</code> to\ndrop the numbers. Running the live example sends its edited source to the official Rust\nPlayground. To change highlighting and numbering for the whole blog, see <code>code</code> in\n<code>openblog.json</code>.</p>\n<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>\n<section class=\"ob-knowledge-check\" aria-label=\"Knowledge check\">\n<div class=\"ob-quiz\">\n<p class=\"ob-quiz-prompt\"><strong>What happens when a post is dated in the future?</strong></p>\n<ol class=\"ob-quiz-choices\" type=\"A\">\n<li>It is published immediately with a future date</li>\n<li>It stays hidden until a build runs after the scheduled time</li>\n<li>It is automatically saved as a draft</li>\n</ol>\n<div class=\"ob-quiz-answer\">\n<p>Answer: B. It stays hidden until a build runs after the scheduled time</p>\n<p>A future-dated post becomes public in the first build run after its scheduled time.</p>\n</div>\n</div>\n</section>\n<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>\n<p>Put files in <code>static/</code>; they are copied to the site root. <code>static/images/photo.png</code> is\n<code>/images/photo.png</code>:</p>\n<pre><code class=\"language-markdown\">![A short description](/images/photo.png)\n</code></pre>\n<p>The admin editor uploads and inserts images for you, including by drag and drop or paste.</p>\n<p>Next: <a href=\"https://open-blog-jtc.netlify.app/posts/tags-and-series/\">Tags and series</a>.</p>\n<div class=\"footnote-definition\" id=\"1\"><sup class=\"footnote-definition-label\">1</sup>\n<p>Footnotes render at the end of the post.</p>\n</div>\n<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>\n",
      "content_text": "Writing a post\nCanonical: https://open-blog-jtc.netlify.app/posts/writing-a-post/\nFront matter, Markdown, images, and code blocks in one file.\nA post is a Markdown file in content/posts/. The file name can start with a date\n(2026-01-12-writing-a-post.md); the rest becomes the slug, so this post lives at\n/posts/writing-a-post/. Add slug: to the front matter to choose a different one.\nFront matter\n---\ntitle: Writing a post\nsubtitle: Optional. A one-line subheading shown under the title.\ndate: 2026-01-12           # or a full time: 2026-01-12T09:30:00Z\ntags: [guide, markdown]    # inline lists work too\ndescription: Optional. Used in feeds and search results.\ncover: /images/cover.png   # optional; the first image in the body is the fallback\ndraft: false\n---\nDates without a time are midnight UTC. A post dated in the future is scheduled and stays\nhidden until that moment (part three has the details).\nMarkdown that works\nCommonMark plus the GitHub extensions: tables, task lists, footnotes, and strikethrough.\nHeadings get ids and anchor links, so #markdown-that-works links here.\nFeature\nSyntax\nTask list\n- [x] done\nFootnote\ntext[^1]\nStrikethrough\n~~old~~\nWrite the post\nPublish it\nCallouts draw attention to a note, a tip, or a warning:\nTip:\nWrite > [!NOTE], > [!TIP], > [!IMPORTANT], > [!WARNING], or > [!CAUTION]\non the first line of a quote.\nRegular code blocks are read-only: they keep the original syntax colouring, line numbers,\nhighlighted lines, and copy button. This one demonstrates that decorative presentation:\nRead-only example · src/lib.rs\npub fn greeting(name: &str) -> String {\nformat!(\"Hello, {name}!\")\n}\nAdd runnable only when readers should be able to edit and execute a self-contained Rust\nexample. A runnable block deliberately becomes an editor with controls and inline output:\nLive example · try changing the name\nfn main() {\nlet name = \"reader\";\nprintln!(\"Hello, {name}!\");\n}\nRun and edit this example on the canonical article (https://open-blog-jtc.netlify.app/posts/writing-a-post/).\nThe two fences begin with ```rust title=\"...\" and\n```rust runnable playgroundLink=false title=\"...\" respectively. Leave out\nplaygroundLink=false when you want the external Playground fallback. Add\nshowLineNumbers=10 to a read-only block to count from 10, or showLineNumbers=false to\ndrop the numbers. Running the live example sends its edited source to the official Rust\nPlayground. To change highlighting and numbering for the whole blog, see code in\nopenblog.json.\nCheck your understanding\nQuestion: What happens when a post is dated in the future?\nIt is published immediately with a future date\nIt stays hidden until a build runs after the scheduled time\nIt is automatically saved as a draft\nAnswer: 2. It stays hidden until a build runs after the scheduled time\nExplanation: A future-dated post becomes public in the first build run after its scheduled time.\nImages\nPut files in static/; they are copied to the site root. static/images/photo.png is\n/images/photo.png:\n![A short description](/images/photo.png)\nThe admin editor uploads and inserts images for you, including by drag and drop or paste.\nNext: Tags and series (https://open-blog-jtc.netlify.app/posts/tags-and-series/).\n[1]: Footnotes render at the end of the post.\nPortable fallback: The source code and canonical run/edit link are preserved; eligible Rust examples also link to the external Playground. Review: Review the preserved source and keep the canonical link for editing or execution.\nPortable fallback: The question and answer are preserved; scoring, retry, and remembered attempts are unavailable. Review: Review the static question and answer; keep the canonical link when scoring or retries matter.\nJoin the discussion on the canonical article (https://open-blog-jtc.netlify.app/posts/writing-a-post/#ob-discussion)",
      "date_published": "2026-01-12T00:00:00Z",
      "id": "https://open-blog-jtc.netlify.app/posts/writing-a-post/",
      "summary": "What goes in a post file, which Markdown features work, and how images and code blocks are handled.",
      "tags": [
        "guide",
        "markdown"
      ],
      "title": "Writing a post",
      "url": "https://open-blog-jtc.netlify.app/posts/writing-a-post/"
    },
    {
      "content_html": "<p>You are looking at <code>content/posts/2026-01-05-welcome-to-your-blog.md</code>. Everything on this\nsite comes from Markdown files like it. There is no database to set up and nothing to\nexport later: your posts are plain text in a folder you own.</p>\n<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>\n<ol>\n<li><strong>A text editor.</strong> Open the file, change it, save. <code>openblog serve</code> rebuilds the site\nwhile it runs.</li>\n<li><strong>The admin editor.</strong> Run <code>openblog user add you</code>, then <code>openblog serve --admin</code> and\nopen <code>/admin</code>. It edits these same files, with a live preview.</li>\n<li><strong>The command line.</strong> <code>openblog new \"A post title\"</code> creates a file with today's date.</li>\n</ol>\n<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>\n<p>The block between the <code>---</code> lines at the top is the front matter. Only <code>date</code> is required,\nplus 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;\nthe <a href=\"https://open-blog-jtc.netlify.app/series/getting-started/\">Getting started</a> series walks through them.</p>\n<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>\n<ul>\n<li>Set the title, description, author, and address in <code>openblog.json</code>.</li>\n<li>Replace this post, or keep it as a reminder of how the pieces fit.</li>\n<li>Pick a theme in <code>openblog.json</code>, or write one in <code>themes/</code>.</li>\n</ul>\n<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>\n",
      "content_text": "Welcome to your blog\nCanonical: https://open-blog-jtc.netlify.app/posts/welcome-to-your-blog/\nYou are looking at content/posts/2026-01-05-welcome-to-your-blog.md. Everything on this\nsite comes from Markdown files like it. There is no database to set up and nothing to\nexport later: your posts are plain text in a folder you own.\nThree ways to write\nA text editor. Open the file, change it, save. openblog serve rebuilds the site\nwhile it runs.\nThe admin editor. Run openblog user add you, then openblog serve --admin and\nopen /admin. It edits these same files, with a live preview.\nThe command line. openblog new \"A post title\" creates a file with today's date.\nWhat a post needs\nThe block between the --- lines at the top is the front matter. Only date is required,\nplus a title unless the body starts with a # heading. tags, description, series, cover, draft, and theme are optional;\nthe Getting started (https://open-blog-jtc.netlify.app/series/getting-started/) series walks through them.\nMake it yours\nSet the title, description, author, and address in openblog.json.\nReplace this post, or keep it as a reminder of how the pieces fit.\nPick a theme in openblog.json, or write one in themes/.\nJoin the discussion on the canonical article (https://open-blog-jtc.netlify.app/posts/welcome-to-your-blog/#ob-discussion)",
      "date_published": "2026-01-05T00:00:00Z",
      "id": "https://open-blog-jtc.netlify.app/posts/welcome-to-your-blog/",
      "summary": "This is the first post on a fresh open.blog. Edit it, or delete it, to make the blog yours.",
      "tags": [
        "meta"
      ],
      "title": "Welcome to your blog",
      "url": "https://open-blog-jtc.netlify.app/posts/welcome-to-your-blog/"
    }
  ],
  "language": "en",
  "title": "open.blog",
  "version": "https://jsonfeed.org/version/1.1"
}