<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>Krios CMS Blog</title>
        <link>https://krios-cms-docs.vercel.app/blog</link>
        <description>Krios CMS Blog</description>
        <lastBuildDate>Wed, 24 Jun 2026 00:00:00 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <item>
            <title><![CDATA[Rich-text links + isLocalizable is now immutable once content exists]]></title>
            <link>https://krios-cms-docs.vercel.app/blog/2026/06/24/rich-text-links</link>
            <guid>https://krios-cms-docs.vercel.app/blog/2026/06/24/rich-text-links</guid>
            <pubDate>Wed, 24 Jun 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[The link mark lands across authoring, storage, validation, and both delivery paths. Plus a guardrail that stops isLocalizable from being flipped after a field has data.]]></description>
            <content:encoded><![CDATA[<p>A new inline mark for rich text and a content-modeling guardrail landed this round.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_LPuF" id="links-in-rich-text">Links in rich text<a href="https://krios-cms-docs.vercel.app/blog/2026/06/24/rich-text-links#links-in-rich-text" class="hash-link" aria-label="Direct link to Links in rich text" title="Direct link to Links in rich text" translate="no">​</a></h2>
<p>Rich text gained a <code>link</code> mark, so a run of text can now carry a hyperlink end to
end — from the TipTap editor through storage, validation, and both delivery
projections.</p>
<p>The mark sits alongside the existing formatting marks and adds two fields:</p>
<div class="language-json codeBlockContainer_OehM theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_eqps"><pre tabindex="0" class="prism-code language-json codeBlock_pft9 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_muV3"><div class="token-line" style="color:#F8F8F2"><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> </span><span class="token property">"type"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"link"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token property">"href"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"/about"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token property">"title"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"About us"</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><br></div></code></pre></div></div>
<ul>
<li class=""><strong><code>href</code></strong> is required. It must be an absolute <code>http</code>/<code>https</code> URL, a
<code>mailto:</code>/<code>tel:</code> link, or a relative path. Unsafe schemes like <code>javascript:</code>
are rejected on write, and sanitized again at render time as defense in depth.</li>
<li class=""><strong><code>title</code></strong> is optional and maps to the anchor's <code>title</code> attribute.</li>
</ul>
<p>The <code>html</code> projection renders <code>&lt;a href="…"&gt;</code>, adding <code>rel="noopener noreferrer"</code>
on external links (and a <code>title</code> attribute when present). This works identically
on the <strong>GraphQL and REST</strong> delivery paths. The HTML-paste cleaner (<code>from-html</code>)
preserves anchors, so pasting from Word / Google Docs keeps links intact.</p>
<p>The <code>href</code> is a plain string today; the AST shape leaves room for a future
entry-reference link variant without breaking stored content.</p>
<h3 class="anchor anchorTargetStickyNavbar_LPuF" id="react">React<a href="https://krios-cms-docs.vercel.app/blog/2026/06/24/rich-text-links#react" class="hash-link" aria-label="Direct link to React" title="Direct link to React" translate="no">​</a></h3>
<p><a class="" href="https://krios-cms-docs.vercel.app/sdk/react"><code>@krios/react</code></a>'s <code>KriosRichText</code> handles the <code>link</code> mark out of the
box — the default renderer receives <code>href</code> + optional <code>title</code>, sanitizes the href,
and adds <code>rel="noopener noreferrer"</code> on external links. Override it like any other
mark renderer for full control.</p>
<p>See <a class="" href="https://krios-cms-docs.vercel.app/content-modeling/rich-text">Rich Text</a> for the full AST reference.</p>
<h2 class="anchor anchorTargetStickyNavbar_LPuF" id="islocalizable-is-now-immutable-once-a-field-has-content"><code>isLocalizable</code> is now immutable once a field has content<a href="https://krios-cms-docs.vercel.app/blog/2026/06/24/rich-text-links#islocalizable-is-now-immutable-once-a-field-has-content" class="hash-link" aria-label="Direct link to islocalizable-is-now-immutable-once-a-field-has-content" title="Direct link to islocalizable-is-now-immutable-once-a-field-has-content" translate="no">​</a></h2>
<p>Shared and per-locale values use different storage keys, so flipping
<code>isLocalizable</code> after a field already has data would orphan the existing values.
The field-update API now guards against this: changing the flag once any value has
been written returns <code>409 is_localizable_immutable</code>. Set it correctly at field
creation time.</p>
<p><code>isSortable</code> and <code>isFilterable</code> remain mutable. See <a class="" href="https://krios-cms-docs.vercel.app/content-modeling/flags">Flags</a>
for the full matrix.</p>]]></content:encoded>
            <category>rich-text</category>
            <category>delivery</category>
            <category>content-modeling</category>
        </item>
        <item>
            <title><![CDATA[Localized media alt text + inline rich-text images]]></title>
            <link>https://krios-cms-docs.vercel.app/blog/2026/05/29/media-alt-and-inline-images</link>
            <guid>https://krios-cms-docs.vercel.app/blog/2026/05/29/media-alt-and-inline-images</guid>
            <pubDate>Fri, 29 May 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[MediaAsset now exposes locale-resolved altText/title/description, and inline rich-text images render with a real src.]]></description>
            <content:encoded><![CDATA[<p>Two delivery improvements landed for media and rich text.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_LPuF" id="localized-alttext--title--description-on-mediaasset">Localized <code>altText</code> / <code>title</code> / <code>description</code> on <code>MediaAsset</code><a href="https://krios-cms-docs.vercel.app/blog/2026/05/29/media-alt-and-inline-images#localized-alttext--title--description-on-mediaasset" class="hash-link" aria-label="Direct link to localized-alttext--title--description-on-mediaasset" title="Direct link to localized-alttext--title--description-on-mediaasset" translate="no">​</a></h2>
<p>The GraphQL <code>MediaAsset</code> type now exposes the asset's locale overlay directly:</p>
<div class="language-graphql codeBlockContainer_OehM theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_eqps"><pre tabindex="0" class="prism-code language-graphql codeBlock_pft9 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_muV3"><div class="token-line" style="color:#F8F8F2"><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">type</span><span class="token plain"> </span><span class="token class-name">MediaAsset</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token comment" style="color:rgb(98, 114, 164)"># …</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token attr-name" style="color:rgb(241, 250, 140)">altText</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token scalar">String</span><span class="token plain">       </span><span class="token comment" style="color:rgb(98, 114, 164)"># resolved from the MediaAssetLocale overlay</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token attr-name" style="color:rgb(241, 250, 140)">title</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token scalar">String</span><span class="token plain">         </span><span class="token comment" style="color:rgb(98, 114, 164)"># for the request locale</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token attr-name" style="color:rgb(241, 250, 140)">description</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token scalar">String</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><br></div></code></pre></div></div>
<p>These resolve against the <strong>request locale</strong> — the containing entry's locale for an
embedded <code>media</code> field, the link's parent locale for a link asset, or the new <code>locale</code>
argument on the top-level <code>asset(id, locale)</code> query. When no overlay row exists for that
locale, the field is <code>null</code>. Batched through a DataLoader, so selecting it across many
assets stays a single query.</p>
<p>This makes the asset the single, DRY source of alt text — you no longer need a sibling
<code>…Alt</code> field on every media field, and the text localizes with the asset. The REST asset
endpoint (<code>media/{id}?locale=</code>) continues to merge the same overlay.</p>
<p><code>krios types generate</code> now includes these fields on the generated <code>MediaAsset</code> interface.</p>
<h2 class="anchor anchorTargetStickyNavbar_LPuF" id="inline-rich-text-images-render-with-a-resolved-src">Inline rich-text images render with a resolved <code>src</code><a href="https://krios-cms-docs.vercel.app/blog/2026/05/29/media-alt-and-inline-images#inline-rich-text-images-render-with-a-resolved-src" class="hash-link" aria-label="Direct link to inline-rich-text-images-render-with-a-resolved-src" title="Direct link to inline-rich-text-images-render-with-a-resolved-src" translate="no">​</a></h2>
<p><code>embeddedAsset</code> nodes in a rich-text body now render as a real <code>&lt;img src="…" alt="…"&gt;</code>
in the delivery <code>html</code> — the CDN URL is resolved server-side on <strong>both</strong> the GraphQL and
REST delivery paths. Previously the <code>&lt;img&gt;</code> came back without a <code>src</code> and silently failed
to load, which meant inline images had to be rendered from the raw AST by hand.</p>
<p><code>embeddedEntry</code> nodes are unchanged: they still render as a
<code>&lt;div data-krios-entry-id="…" data-krios-content-type="…"&gt;</code> placeholder for the client to
hydrate. So inline <strong>images</strong> now Just Work, and only embedded <strong>entries</strong> need a custom
component.</p>
<p>See <a class="" href="https://krios-cms-docs.vercel.app/content-management/media">Media</a> and <a class="" href="https://krios-cms-docs.vercel.app/content-modeling/rich-text">Rich Text</a> for details.</p>]]></content:encoded>
            <category>delivery</category>
            <category>media</category>
            <category>rich-text</category>
        </item>
        <item>
            <title><![CDATA[Krios CMS V1 Launch]]></title>
            <link>https://krios-cms-docs.vercel.app/blog/2026/05/05/v1-launch</link>
            <guid>https://krios-cms-docs.vercel.app/blog/2026/05/05/v1-launch</guid>
            <pubDate>Tue, 05 May 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Initial release of Krios CMS]]></description>
            <content:encoded><![CDATA[<p>Krios CMS V1 is here. Schema-first, API-first, pure headless CMS built for agencies and enterprises.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_LPuF" id="whats-included">What's Included<a href="https://krios-cms-docs.vercel.app/blog/2026/05/05/v1-launch#whats-included" class="hash-link" aria-label="Direct link to What's Included" title="Direct link to What's Included" translate="no">​</a></h2>
<ul>
<li class="">Content modeling with 11 field types + custom field types</li>
<li class="">Content tree with folders as content types</li>
<li class="">GraphQL and REST delivery APIs</li>
<li class="">Multi-site, multi-tenant, multi-environment</li>
<li class="">Localization with per-field locale control</li>
<li class="">TipTap rich text editor</li>
<li class="">Media management with Supabase CDN</li>
<li class="">Preview with signed tokens</li>
<li class="">Configurable workflows and approval chains</li>
<li class="">Translation workflows</li>
<li class="">Advanced search with Meilisearch</li>
<li class="">Real-time collaboration</li>
<li class="">Governance intelligence</li>
<li class="">And much more</li>
</ul>
<p><a class="" href="https://krios-cms-docs.vercel.app/">Read the full documentation →</a></p>]]></content:encoded>
            <category>release</category>
        </item>
    </channel>
</rss>