<?xml version="1.0" encoding="UTF-8" standalone="no"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:idx="urn:atom-extension:indexing" xmlns:media="http://search.yahoo.com/mrss/" idx:index="no"><subtitle>tipy na zajímavé články</subtitle>
    <!--
Content-type: Preventing XSRF in IE.

-->
    <generator uri="https://cloud.feedly.com">feedly cloud</generator>
    <id>tag:feedly.com,2013:cloud/feed/https://feedly.com/f/rJIIpYUxxvSQIe3s6CKpJaO8</id>
    <link href="https://feedly.com/f/rJIIpYUxxvSQIe3s6CKpJaO8" rel="self" type="application/rss+xml"/>
    <link href="https://feedly.com/f/rJIIpYUxxvSQIe3s6CKpJaO8?continuation=19de73be197:21797a:bfc602cd" rel="next" type="application/rss+xml"/>
    <title>rarouš.w3b</title>
    <updated>2026-08-12T19:34:25Z</updated>
    <entry>
        <id>tag:feedly.com,2013:cloud/entry/cOXRjoksGIQzU1pdqbdybn+OTWYeI0riptNneGckdsI=_19ff777f553:fc6b11:10e6f064</id>
        <title type="html">AI Software Development - What Does The Data Say? - Codemanship's Blog</title>
        <published>2026-08-12T19:34:21Z</published>
        <updated>2026-08-12T19:34:25Z</updated>
        <link href="https://codemanship.wordpress.com/2026/08/12/ai-software-development-what-does-the-data-say/" rel="alternate" type="text/html"/>
        <summary type="html">I’m currently pulling together a bunch of sources – that are mostly recent – on the topic of LLMs and their use in software development. Some are peer-reviewed studies. Some are i…</summary>
        <content type="html">&lt;html lang="en" class="js wf-alegreyasans-n7-active wf-alegreyasans-n4-active wf-alegreyasans-i7-active wf-alegreyasans-i4-active wf-active" data-lt-installed="true"&gt;&lt;head&gt;
	&lt;meta charset="UTF-8"&gt;
	&lt;meta name="viewport" content="width=device-width, initial-scale=1"&gt;
	&lt;link rel="profile" href="https://gmpg.org/xfn/11"&gt;
		&lt;link rel="pingback" href="https://codemanship.wordpress.com/xmlrpc.php"&gt;
		&lt;script src="/wp-content/plugins/custom-fonts/js/webfont.js" type="text/javascript" async=""&gt;&lt;/script&gt;&lt;script&gt;(function(html){html.className = html.className.replace(/\bno-js\b/,'js')})(document.documentElement);&lt;/script&gt;
&lt;title&gt;AI Software Development – What Does The Data Say? – Codemanship's Blog&lt;/title&gt;
&lt;script type="text/javascript"&gt;
  WebFontConfig = {"google":{"families":["Alegreya+Sans:r:latin,latin-ext","Alegreya+Sans:r,i,b,bi:latin,latin-ext"]},"api_url":"https:\/\/fonts-api.wp.com\/css"};
  (function() {
    var wf = document.createElement('script');
    wf.src = '/wp-content/plugins/custom-fonts/js/webfont.js';
    wf.type = 'text/javascript';
    wf.async = 'true';
    var s = document.getElementsByTagName('script')[0];
    s.parentNode.insertBefore(wf, s);
	})();
&lt;/script&gt;&lt;style id="jetpack-custom-fonts-css"&gt;.wf-active body, .wf-active button, .wf-active input, .wf-active select, .wf-active textarea{font-family:"Alegreya Sans",sans-serif}.wf-active ::-webkit-input-placeholder{font-family:"Alegreya Sans",sans-serif}.wf-active :-moz-placeholder{font-family:"Alegreya Sans",sans-serif}.wf-active ::-moz-placeholder{font-family:"Alegreya Sans",sans-serif}.wf-active :-ms-input-placeholder{font-family:"Alegreya Sans",sans-serif}.wf-active button, .wf-active button[disabled]:hover, .wf-active button[disabled]:focus, .wf-active input[type="button"], .wf-active input[type="button"][disabled]:hover, .wf-active input[type="button"][disabled]:focus, .wf-active input[type="reset"], .wf-active input[type="reset"][disabled]:hover, .wf-active input[type="reset"][disabled]:focus, .wf-active input[type="submit"], .wf-active input[type="submit"][disabled]:hover, .wf-active input[type="submit"][disabled]:focus, .wf-active .main-navigation, .wf-active .no-comments, .wf-active .tagcloud a, .wf-active .wp_widget_tag_cloud a, .wf-active .top_rated div &gt; p, .wf-active .comments-area #respond .comment-form-fields p.comment-form-posting-as, .wf-active .comments-area #respond .comment-form-fields p.comment-form-log-out, .wf-active .comments-area #respond #comment-form-identity #comment-form-nascar p, .wf-active .comments-area #respond #comment-form-subscribe p, .wf-active .comments-area #respond p.form-submit input#comment-submit, .wf-active .comment-content p.comment-likes span.comment-like-feedback, .wf-active .jp-relatedposts-post-date, .wf-active .jp-relatedposts-post-context{font-family:"Alegreya Sans",sans-serif}.wf-active .post-password-form label, .wf-active .comment-form label, .wf-active .entry-content .contact-form label, .wf-active .post-navigation .meta-nav, .wf-active .image-navigation, .wf-active .comment-navigation, .wf-active .menu-toggle, .wf-active .widget_recent_entries .post-date, .wf-active .widget_rss .rss-date, .wf-active .widget_rss cite, .wf-active .sticky-post, .wf-active .entry-footer, .wf-active .comment-metadata, .wf-active .pingback .edit-link, .wf-active .comment-reply-link, .wf-active .page-links, .wf-active .page-links a, .wf-active .page-links &gt; span, .wf-active .pd-rating, .wf-active .entry-content .portfolio-entry-meta, .wf-active .entry-content #jp-relatedposts h3.jp-relatedposts-headline, .wf-active .hentry div.sharedaddy h3.sd-title, .wf-active .hentry h3.sd-title{font-family:"Alegreya Sans",sans-serif}.wf-active .pagination{font-family:"Alegreya Sans",sans-serif}.wf-active body:not(.logged-in) .site .skip-link{font-family:"Alegreya Sans",sans-serif}.wf-active .site-description, .wf-active .author-bio, .wf-active .taxonomy-description, .wf-active .entry-caption, .wf-active .comment-notes, .wf-active .comment-awaiting-moderation, .wf-active .logged-in-as, .wf-active .form-allowed-tags, .wf-active .site-info, .wf-active .wp-caption .wp-caption-text, .wf-active .gallery-caption, .wf-active .entry-content .portfolio-entry-content p, .wf-active .entry-content .testimonial-entry-title, .wf-active .entry-content .testimonial-entry-content p, .wf-active .entry-content #jp-relatedposts .jp-relatedposts-items p, .wf-active .entry-content #jp-relatedposts .jp-relatedposts-items-visual h4.jp-relatedposts-post-title{font-family:"Alegreya Sans",sans-serif}.wf-active .site-title, .wf-active .post-navigation .post-title, .wf-active .comments-title, .wf-active .comment-reply-title, .wf-active .page-title{font-family:"Alegreya Sans",sans-serif;font-style:normal;font-weight:400}.wf-active .widget .widget-title, .wf-active .entry-content .portfolio-entry-title{font-family:"Alegreya Sans",sans-serif;font-style:normal;font-weight:400}.wf-active .entry-title{font-family:"Alegreya Sans",sans-serif;font-style:normal;font-weight:400}.wf-active .format-aside .entry-title, .wf-active .format-image .entry-title, .wf-active .format-video .entry-title, .wf-active .format-quote .entry-title, .wf-active .format-gallery .entry-title, .wf-active .format-status .entry-title, .wf-active .format-link .entry-title, .wf-active .format-audio .entry-title, .wf-active .format-chat .entry-title{font-style:normal;font-weight:400}@media screen and (min-width: 44.375em){.wf-active .site-title, .wf-active .post-navigation .post-title{font-style:normal;font-weight:400}}@media screen and (min-width: 44.375em){.wf-active .entry-title{font-style:normal;font-weight:400}}@media screen and (min-width: 61.5625em){.wf-active .entry-title{font-style:normal;font-weight:400}}@media screen and (min-width: 61.5625em){.wf-active .format-aside .entry-title, .wf-active .format-image .entry-title, .wf-active .format-video .entry-title, .wf-active .format-quote .entry-title, .wf-active .format-gallery .entry-title, .wf-active .format-status .entry-title, .wf-active .format-link .entry-title, .wf-active .format-audio .entry-title, .wf-active .format-chat .entry-title{font-style:normal;font-weight:400}}&lt;/style&gt;
&lt;meta name="robots" content="max-image-preview:large"&gt;
&lt;link rel="dns-prefetch" href="//s0.wp.com"&gt;
&lt;link rel="dns-prefetch" href="//widgets.wp.com"&gt;
&lt;link rel="alternate" type="application/rss+xml" title="Codemanship's Blog » Feed" href="https://codemanship.wordpress.com/feed/"&gt;
&lt;link rel="alternate" type="application/rss+xml" title="Codemanship's Blog » Comments Feed" href="https://codemanship.wordpress.com/comments/feed/"&gt;
&lt;link rel="alternate" type="application/rss+xml" title="Codemanship's Blog » AI Software Development – What Does The Data&amp;nbsp;Say? Comments Feed" href="https://codemanship.wordpress.com/2026/08/12/ai-software-development-what-does-the-data-say/feed/"&gt;
	&lt;script type="text/javascript"&gt;
		/* &lt;![CDATA[ */
		function addLoadEvent(func) {
			var oldonload = window.onload;
			if (typeof window.onload != 'function') {
				window.onload = func;
			} else {
				window.onload = function () {
					oldonload();
					func();
				}
			}
		}
		/* ]]&gt; */
	&lt;/script&gt;
	&lt;style id="wp-img-auto-sizes-contain-inline-css"&gt;
img:is([sizes=auto i],[sizes^="auto," i]){contain-intrinsic-size:3000px 1500px}
/*# sourceURL=wp-img-auto-sizes-contain-inline-css */
&lt;/style&gt;
&lt;link crossorigin="anonymous" rel="stylesheet" id="all-css-2-1" href="/_static/??-eJyVjMEKwjAQRH/IuOrB4kH8lpAOmjabXdwNrX9vK4LgQZCBgQczjyYNSaqjOnELWto1V6MBrjGNbyYWWatvBUZ+AyO4SDFKwhqdfFr+D8uzA3WbzDb0v/eOEh19UDH/ol/Kkkd8xC9a5xc+77tud1pyOA5PXPBXBA==&amp;amp;cssminify=yes" type="text/css" media="all"&gt;
&lt;style id="wp-emoji-styles-inline-css"&gt;

	img.wp-smiley, img.emoji {
		display: inline !important;
		border: none !important;
		box-shadow: none !important;
		height: 1em !important;
		width: 1em !important;
		margin: 0 0.07em !important;
		vertical-align: -0.1em !important;
		background: none !important;
		padding: 0 !important;
	}
/*# sourceURL=wp-emoji-styles-inline-css */
&lt;/style&gt;
&lt;style id="wp-block-library-inline-css"&gt;
:root{--wp-block-synced-color:#7a00df;--wp-block-synced-color--rgb:122,0,223;--wp-bound-block-color:var(--wp-block-synced-color);--wp-editor-canvas-background:#ddd;--wp-admin-theme-color:#007cba;--wp-admin-theme-color--rgb:0,124,186;--wp-admin-theme-color-darker-10:#006ba1;--wp-admin-theme-color-darker-10--rgb:0,107,160.5;--wp-admin-theme-color-darker-20:#005a87;--wp-admin-theme-color-darker-20--rgb:0,90,135;--wp-admin-border-width-focus:2px}@media (min-resolution:192dpi){:root{--wp-admin-border-width-focus:1.5px}}.wp-element-button{cursor:pointer}:root .has-very-light-gray-background-color{background-color:#eee}:root .has-very-dark-gray-background-color{background-color:#313131}:root .has-very-light-gray-color{color:#eee}:root .has-very-dark-gray-color{color:#313131}:root .has-vivid-green-cyan-to-vivid-cyan-blue-gradient-background{background:linear-gradient(135deg,#00d084,#0693e3)}:root .has-purple-crush-gradient-background{background:linear-gradient(135deg,#34e2e4,#4721fb 50%,#ab1dfe)}:root .has-hazy-dawn-gradient-background{background:linear-gradient(135deg,#faaca8,#dad0ec)}:root .has-subdued-olive-gradient-background{background:linear-gradient(135deg,#fafae1,#67a671)}:root .has-atomic-cream-gradient-background{background:linear-gradient(135deg,#fdd79a,#004a59)}:root .has-nightshade-gradient-background{background:linear-gradient(135deg,#330968,#31cdcf)}:root .has-midnight-gradient-background{background:linear-gradient(135deg,#020381,#2874fc)}:root{--wp--preset--font-size--normal:16px;--wp--preset--font-size--huge:42px}.has-regular-font-size{font-size:1em}.has-larger-font-size{font-size:2.625em}.has-normal-font-size{font-size:var(--wp--preset--font-size--normal)}.has-huge-font-size{font-size:var(--wp--preset--font-size--huge)}:root .has-text-align-center{text-align:center}:root .has-text-align-left{text-align:left}:root .has-text-align-right{text-align:right}.has-fit-text{white-space:nowrap!important}#end-resizable-editor-section{display:none}.aligncenter{clear:both}.items-justified-left{justify-content:flex-start}.items-justified-center{justify-content:center}.items-justified-right{justify-content:flex-end}.items-justified-space-between{justify-content:space-between}.screen-reader-text{word-wrap:normal!important;border:0;clip-path:inset(50%);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px;word-break:normal!important}.screen-reader-text:focus{background-color:#ddd;clip-path:none;color:#444;display:block;font-size:1em;height:auto;left:5px;line-height:normal;padding:15px 23px 14px;text-decoration:none;top:5px;width:auto;z-index:100000}html :where(.has-border-color){border-style:solid}html :where([style^=border-color],[style*=";border-color"],[style*="; border-color"]){border-style:solid}html :where([style^=border-top-color],[style*=";border-top-color"],[style*="; border-top-color"]){border-top-style:solid}html :where([style^=border-right-color],[style*=";border-right-color"],[style*="; border-right-color"]){border-right-style:solid}html :where([style^=border-bottom-color],[style*=";border-bottom-color"],[style*="; border-bottom-color"]){border-bottom-style:solid}html :where([style^=border-left-color],[style*=";border-left-color"],[style*="; border-left-color"]){border-left-style:solid}html :where([style^=border-width],[style*=";border-width"],[style*="; border-width"]){border-style:solid}html :where([style^=border-top-width],[style*=";border-top-width"],[style*="; border-top-width"]){border-top-style:solid}html :where([style^=border-right-width],[style*=";border-right-width"],[style*="; border-right-width"]){border-right-style:solid}html :where([style^=border-bottom-width],[style*=";border-bottom-width"],[style*="; border-bottom-width"]){border-bottom-style:solid}html :where([style^=border-left-width],[style*=";border-left-width"],[style*="; border-left-width"]){border-left-style:solid}html :where(img[class*=wp-image-]){height:auto;max-width:100%}:where(figure){margin:0 0 1em}html :where(.is-position-sticky){--wp-admin--admin-bar--position-offset:var(--wp-admin--admin-bar--height,0px)}@media screen and (max-width:600px){html :where(.is-position-sticky){--wp-admin--admin-bar--position-offset:0px}}

/*# sourceURL=/wp-content/plugins/gutenberg-core/v23.7.1/build/styles/block-library/common.min.css */
&lt;/style&gt;
&lt;style id="wp-block-paragraph-inline-css"&gt;
.is-small-text{font-size:.875em}.is-regular-text{font-size:1em}.is-large-text{font-size:2.25em}.is-larger-text{font-size:3em}.has-drop-cap:not(:focus):first-letter{float:left;font-size:8.4em;font-style:normal;font-weight:100;line-height:.68;margin:.05em .1em 0 0;text-transform:uppercase}body.rtl .has-drop-cap:not(:focus):first-letter{float:none;margin-left:.1em}p.has-drop-cap.has-background{overflow:hidden}:root :where(p.has-background){padding:1.25em 2.375em}:where(p.has-text-color:not(.has-link-color)) a{color:inherit}p.has-text-align-left[style*="writing-mode:vertical-lr"],p.has-text-align-right[style*="writing-mode:vertical-rl"]{rotate:180deg}
/*# sourceURL=/wp-content/plugins/gutenberg-core/v23.7.1/build/styles/block-library/paragraph/style.min.css */
&lt;/style&gt;
&lt;style id="wp-block-library-inline-css-extra"&gt;
.has-text-align-justify {
	text-align:justify;
}
.has-text-align-justify{text-align:justify;}
/*# sourceURL=wp-block-library-inline-css */
&lt;/style&gt;

&lt;style id="classic-theme-styles-inline-css"&gt;
.wp-block-button__link{background-color:#32373c;border-radius:9999px;box-shadow:none;color:#fff;font-size:1.125em;padding:calc(.667em + 2px) calc(1.333em + 2px);text-decoration:none}.wp-block-file__button{background:#32373c;color:#fff}.wp-block-accordion-heading{margin:0}.wp-block-accordion-heading__toggle{background-color:inherit!important;color:inherit!important}.wp-block-accordion-heading__toggle:not(:focus-visible){outline:none}.wp-block-accordion-heading__toggle:focus,.wp-block-accordion-heading__toggle:hover{background-color:inherit!important;border:none;box-shadow:none;color:inherit;padding:var(--wp--preset--spacing--20,1em) 0;text-decoration:none}.wp-block-accordion-heading__toggle:focus-visible{outline:auto;outline-offset:0}.wp-block-tab:not(.has-text-color){color:inherit!important}.wp-block-tab:not(.has-background){background-color:inherit!important}.wp-block-tab:focus,.wp-block-tab:hover{text-decoration:none}.wp-block-tab:focus-visible{outline:auto;outline-offset:0}
/*# sourceURL=/wp-content/plugins/gutenberg-core/v23.7.1/build/styles/block-library/classic.min.css */
&lt;/style&gt;

&lt;style id="coblocks-inline-format-inline-css"&gt;
.uppercase{text-transform:uppercase}
/*# sourceURL=coblocks-inline-format-inline-css */
&lt;/style&gt;
&lt;link crossorigin="anonymous" rel="stylesheet" id="all-css-12-1" href="/_static/??-eJx9jEEOAiEQBD/kQECjeDC+ZWEnijIwYWA3/l72op689KFTVXplCCU3zE1z6reYRYfiUwlP0VYZpwxIJE4IFRd10HOU9iFA2iuhCiI7/ROiDt9WxfETT20jCOc4YUIa2D9t5eGA91xRBMZS7ATtPkTZvCtdzNEZt7f2fHq8Afl7R7w=&amp;amp;cssminify=yes" type="text/css" media="all"&gt;
&lt;style id="global-styles-inline-css"&gt;
:root{--wp--preset--aspect-ratio--square: 1;--wp--preset--aspect-ratio--4-3: 4/3;--wp--preset--aspect-ratio--3-4: 3/4;--wp--preset--aspect-ratio--3-2: 3/2;--wp--preset--aspect-ratio--2-3: 2/3;--wp--preset--aspect-ratio--16-9: 16/9;--wp--preset--aspect-ratio--9-16: 9/16;--wp--preset--color--black: #000000;--wp--preset--color--cyan-bluish-gray: #abb8c3;--wp--preset--color--white: #fff;--wp--preset--color--pale-pink: #f78da7;--wp--preset--color--vivid-red: #cf2e2e;--wp--preset--color--luminous-vivid-orange: #ff6900;--wp--preset--color--luminous-vivid-amber: #fcb900;--wp--preset--color--light-green-cyan: #7bdcb5;--wp--preset--color--vivid-green-cyan: #00d084;--wp--preset--color--pale-cyan-blue: #8ed1fc;--wp--preset--color--vivid-cyan-blue: #0693e3;--wp--preset--color--vivid-purple: #9b51e0;--wp--preset--color--dark-gray: #1a1a1a;--wp--preset--color--medium-gray: #686868;--wp--preset--color--light-gray: #e5e5e5;--wp--preset--color--blue-gray: #4d545c;--wp--preset--color--bright-blue: #007acc;--wp--preset--color--light-blue: #9adffd;--wp--preset--color--dark-brown: #402b30;--wp--preset--color--medium-brown: #774e24;--wp--preset--color--dark-red: #640c1f;--wp--preset--color--bright-red: #ff675f;--wp--preset--color--yellow: #ffef8e;--wp--preset--gradient--vivid-cyan-blue-to-vivid-purple: linear-gradient(135deg,rgb(6,147,227) 0%,rgb(155,81,224) 100%);--wp--preset--gradient--light-green-cyan-to-vivid-green-cyan: linear-gradient(135deg,rgb(122,220,180) 0%,rgb(0,208,130) 100%);--wp--preset--gradient--luminous-vivid-amber-to-luminous-vivid-orange: linear-gradient(135deg,rgb(252,185,0) 0%,rgb(255,105,0) 100%);--wp--preset--gradient--luminous-vivid-orange-to-vivid-red: linear-gradient(135deg,rgb(255,105,0) 0%,rgb(207,46,46) 100%);--wp--preset--gradient--very-light-gray-to-cyan-bluish-gray: linear-gradient(135deg,rgb(238,238,238) 0%,rgb(169,184,195) 100%);--wp--preset--gradient--cool-to-warm-spectrum: linear-gradient(135deg,rgb(74,234,220) 0%,rgb(151,120,209) 20%,rgb(207,42,186) 40%,rgb(238,44,130) 60%,rgb(251,105,98) 80%,rgb(254,248,76) 100%);--wp--preset--gradient--blush-light-purple: linear-gradient(135deg,rgb(255,206,236) 0%,rgb(152,150,240) 100%);--wp--preset--gradient--blush-bordeaux: linear-gradient(135deg,rgb(254,205,165) 0%,rgb(254,45,45) 50%,rgb(107,0,62) 100%);--wp--preset--gradient--luminous-dusk: linear-gradient(135deg,rgb(255,203,112) 0%,rgb(199,81,192) 50%,rgb(65,88,208) 100%);--wp--preset--gradient--pale-ocean: linear-gradient(135deg,rgb(255,245,203) 0%,rgb(182,227,212) 50%,rgb(51,167,181) 100%);--wp--preset--gradient--electric-grass: linear-gradient(135deg,rgb(202,248,128) 0%,rgb(113,206,126) 100%);--wp--preset--gradient--midnight: linear-gradient(135deg,rgb(2,3,129) 0%,rgb(40,116,252) 100%);--wp--preset--font-size--small: 13px;--wp--preset--font-size--medium: 20px;--wp--preset--font-size--large: 36px;--wp--preset--font-size--x-large: 42px;--wp--preset--font-family--albert-sans: 'Albert Sans', sans-serif;--wp--preset--font-family--alegreya: Alegreya, serif;--wp--preset--font-family--arvo: Arvo, serif;--wp--preset--font-family--bodoni-moda: 'Bodoni Moda', serif;--wp--preset--font-family--bricolage-grotesque: 'Bricolage Grotesque', sans-serif;--wp--preset--font-family--cabin: Cabin, sans-serif;--wp--preset--font-family--chivo: Chivo, sans-serif;--wp--preset--font-family--commissioner: Commissioner, sans-serif;--wp--preset--font-family--cormorant: Cormorant, serif;--wp--preset--font-family--courier-prime: 'Courier Prime', monospace;--wp--preset--font-family--crimson-pro: 'Crimson Pro', serif;--wp--preset--font-family--dm-mono: 'DM Mono', monospace;--wp--preset--font-family--dm-sans: 'DM Sans', sans-serif;--wp--preset--font-family--dm-serif-display: 'DM Serif Display', serif;--wp--preset--font-family--domine: Domine, serif;--wp--preset--font-family--eb-garamond: 'EB Garamond', serif;--wp--preset--font-family--epilogue: Epilogue, sans-serif;--wp--preset--font-family--fahkwang: Fahkwang, sans-serif;--wp--preset--font-family--figtree: Figtree, sans-serif;--wp--preset--font-family--fira-sans: 'Fira Sans', sans-serif;--wp--preset--font-family--fjalla-one: 'Fjalla One', sans-serif;--wp--preset--font-family--fraunces: Fraunces, serif;--wp--preset--font-family--gabarito: Gabarito, system-ui;--wp--preset--font-family--ibm-plex-mono: 'IBM Plex Mono', monospace;--wp--preset--font-family--ibm-plex-sans: 'IBM Plex Sans', sans-serif;--wp--preset--font-family--ibarra-real-nova: 'Ibarra Real Nova', serif;--wp--preset--font-family--instrument-serif: 'Instrument Serif', serif;--wp--preset--font-family--inter: Inter, sans-serif;--wp--preset--font-family--josefin-sans: 'Josefin Sans', sans-serif;--wp--preset--font-family--jost: Jost, sans-serif;--wp--preset--font-family--libre-baskerville: 'Libre Baskerville', serif;--wp--preset--font-family--libre-franklin: 'Libre Franklin', sans-serif;--wp--preset--font-family--literata: Literata, serif;--wp--preset--font-family--lora: Lora, serif;--wp--preset--font-family--merriweather: Merriweather, serif;--wp--preset--font-family--montserrat: Montserrat, sans-serif;--wp--preset--font-family--newsreader: Newsreader, serif;--wp--preset--font-family--noto-sans-mono: 'Noto Sans Mono', sans-serif;--wp--preset--font-family--nunito: Nunito, sans-serif;--wp--preset--font-family--open-sans: 'Open Sans', sans-serif;--wp--preset--font-family--overpass: Overpass, sans-serif;--wp--preset--font-family--pt-serif: 'PT Serif', serif;--wp--preset--font-family--petrona: Petrona, serif;--wp--preset--font-family--piazzolla: Piazzolla, serif;--wp--preset--font-family--playfair-display: 'Playfair Display', serif;--wp--preset--font-family--plus-jakarta-sans: 'Plus Jakarta Sans', sans-serif;--wp--preset--font-family--poppins: Poppins, sans-serif;--wp--preset--font-family--raleway: Raleway, sans-serif;--wp--preset--font-family--roboto: Roboto, sans-serif;--wp--preset--font-family--roboto-slab: 'Roboto Slab', serif;--wp--preset--font-family--rubik: Rubik, sans-serif;--wp--preset--font-family--rufina: Rufina, serif;--wp--preset--font-family--sora: Sora, sans-serif;--wp--preset--font-family--source-sans-3: 'Source Sans 3', sans-serif;--wp--preset--font-family--source-serif-4: 'Source Serif 4', serif;--wp--preset--font-family--space-mono: 'Space Mono', monospace;--wp--preset--font-family--syne: Syne, sans-serif;--wp--preset--font-family--texturina: Texturina, serif;--wp--preset--font-family--urbanist: Urbanist, sans-serif;--wp--preset--font-family--work-sans: 'Work Sans', sans-serif;--wp--preset--spacing--20: 0.44rem;--wp--preset--spacing--30: 0.67rem;--wp--preset--spacing--40: 1rem;--wp--preset--spacing--50: 1.5rem;--wp--preset--spacing--60: 2.25rem;--wp--preset--spacing--70: 3.38rem;--wp--preset--spacing--80: 5.06rem;--wp--preset--shadow--natural: 6px 6px 9px rgba(0, 0, 0, 0.2);--wp--preset--shadow--deep: 12px 12px 50px rgba(0, 0, 0, 0.4);--wp--preset--shadow--sharp: 6px 6px 0px rgba(0, 0, 0, 0.2);--wp--preset--shadow--outlined: 6px 6px 0px -3px rgb(255, 255, 255), 6px 6px rgb(0, 0, 0);--wp--preset--shadow--crisp: 6px 6px 0px rgb(0, 0, 0);}.wp-block-button{--wp--preset--dimension--25: 25%;--wp--preset--dimension--50: 50%;--wp--preset--dimension--75: 75%;--wp--preset--dimension--100: 100%;}:where(body) { margin: 0; }:where(.is-layout-flex){gap: 0.5em;}:where(.is-layout-grid){gap: 0.5em;}body .is-layout-flex{display: flex;}.is-layout-flex{flex-wrap: wrap;align-items: center;}.is-layout-flex &gt; :is(*, div){margin: 0;}body .is-layout-grid{display: grid;}.is-layout-grid &gt; :is(*, div){margin: 0;}body{padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;}:root :where(.wp-element-button, .wp-block-button__link){background-color: #32373c;border-width: 0;color: #fff;font-family: inherit;font-size: inherit;font-style: inherit;font-weight: inherit;letter-spacing: inherit;line-height: inherit;padding-top: calc(0.667em + 2px);padding-right: calc(1.333em + 2px);padding-bottom: calc(0.667em + 2px);padding-left: calc(1.333em + 2px);text-decoration: none;text-transform: inherit;}.has-black-color{color: var(--wp--preset--color--black) !important;}.has-cyan-bluish-gray-color{color: var(--wp--preset--color--cyan-bluish-gray) !important;}.has-white-color{color: var(--wp--preset--color--white) !important;}.has-pale-pink-color{color: var(--wp--preset--color--pale-pink) !important;}.has-vivid-red-color{color: var(--wp--preset--color--vivid-red) !important;}.has-luminous-vivid-orange-color{color: var(--wp--preset--color--luminous-vivid-orange) !important;}.has-luminous-vivid-amber-color{color: var(--wp--preset--color--luminous-vivid-amber) !important;}.has-light-green-cyan-color{color: var(--wp--preset--color--light-green-cyan) !important;}.has-vivid-green-cyan-color{color: var(--wp--preset--color--vivid-green-cyan) !important;}.has-pale-cyan-blue-color{color: var(--wp--preset--color--pale-cyan-blue) !important;}.has-vivid-cyan-blue-color{color: var(--wp--preset--color--vivid-cyan-blue) !important;}.has-vivid-purple-color{color: var(--wp--preset--color--vivid-purple) !important;}.has-dark-gray-color{color: var(--wp--preset--color--dark-gray) !important;}.has-medium-gray-color{color: var(--wp--preset--color--medium-gray) !important;}.has-light-gray-color{color: var(--wp--preset--color--light-gray) !important;}.has-blue-gray-color{color: var(--wp--preset--color--blue-gray) !important;}.has-bright-blue-color{color: var(--wp--preset--color--bright-blue) !important;}.has-light-blue-color{color: var(--wp--preset--color--light-blue) !important;}.has-dark-brown-color{color: var(--wp--preset--color--dark-brown) !important;}.has-medium-brown-color{color: var(--wp--preset--color--medium-brown) !important;}.has-dark-red-color{color: var(--wp--preset--color--dark-red) !important;}.has-bright-red-color{color: var(--wp--preset--color--bright-red) !important;}.has-yellow-color{color: var(--wp--preset--color--yellow) !important;}.has-black-background-color{background-color: var(--wp--preset--color--black) !important;}.has-cyan-bluish-gray-background-color{background-color: var(--wp--preset--color--cyan-bluish-gray) !important;}.has-white-background-color{background-color: var(--wp--preset--color--white) !important;}.has-pale-pink-background-color{background-color: var(--wp--preset--color--pale-pink) !important;}.has-vivid-red-background-color{background-color: var(--wp--preset--color--vivid-red) !important;}.has-luminous-vivid-orange-background-color{background-color: var(--wp--preset--color--luminous-vivid-orange) !important;}.has-luminous-vivid-amber-background-color{background-color: var(--wp--preset--color--luminous-vivid-amber) !important;}.has-light-green-cyan-background-color{background-color: var(--wp--preset--color--light-green-cyan) !important;}.has-vivid-green-cyan-background-color{background-color: var(--wp--preset--color--vivid-green-cyan) !important;}.has-pale-cyan-blue-background-color{background-color: var(--wp--preset--color--pale-cyan-blue) !important;}.has-vivid-cyan-blue-background-color{background-color: var(--wp--preset--color--vivid-cyan-blue) !important;}.has-vivid-purple-background-color{background-color: var(--wp--preset--color--vivid-purple) !important;}.has-dark-gray-background-color{background-color: var(--wp--preset--color--dark-gray) !important;}.has-medium-gray-background-color{background-color: var(--wp--preset--color--medium-gray) !important;}.has-light-gray-background-color{background-color: var(--wp--preset--color--light-gray) !important;}.has-blue-gray-background-color{background-color: var(--wp--preset--color--blue-gray) !important;}.has-bright-blue-background-color{background-color: var(--wp--preset--color--bright-blue) !important;}.has-light-blue-background-color{background-color: var(--wp--preset--color--light-blue) !important;}.has-dark-brown-background-color{background-color: var(--wp--preset--color--dark-brown) !important;}.has-medium-brown-background-color{background-color: var(--wp--preset--color--medium-brown) !important;}.has-dark-red-background-color{background-color: var(--wp--preset--color--dark-red) !important;}.has-bright-red-background-color{background-color: var(--wp--preset--color--bright-red) !important;}.has-yellow-background-color{background-color: var(--wp--preset--color--yellow) !important;}.has-black-border-color{border-color: var(--wp--preset--color--black) !important;}.has-cyan-bluish-gray-border-color{border-color: var(--wp--preset--color--cyan-bluish-gray) !important;}.has-white-border-color{border-color: var(--wp--preset--color--white) !important;}.has-pale-pink-border-color{border-color: var(--wp--preset--color--pale-pink) !important;}.has-vivid-red-border-color{border-color: var(--wp--preset--color--vivid-red) !important;}.has-luminous-vivid-orange-border-color{border-color: var(--wp--preset--color--luminous-vivid-orange) !important;}.has-luminous-vivid-amber-border-color{border-color: var(--wp--preset--color--luminous-vivid-amber) !important;}.has-light-green-cyan-border-color{border-color: var(--wp--preset--color--light-green-cyan) !important;}.has-vivid-green-cyan-border-color{border-color: var(--wp--preset--color--vivid-green-cyan) !important;}.has-pale-cyan-blue-border-color{border-color: var(--wp--preset--color--pale-cyan-blue) !important;}.has-vivid-cyan-blue-border-color{border-color: var(--wp--preset--color--vivid-cyan-blue) !important;}.has-vivid-purple-border-color{border-color: var(--wp--preset--color--vivid-purple) !important;}.has-dark-gray-border-color{border-color: var(--wp--preset--color--dark-gray) !important;}.has-medium-gray-border-color{border-color: var(--wp--preset--color--medium-gray) !important;}.has-light-gray-border-color{border-color: var(--wp--preset--color--light-gray) !important;}.has-blue-gray-border-color{border-color: var(--wp--preset--color--blue-gray) !important;}.has-bright-blue-border-color{border-color: var(--wp--preset--color--bright-blue) !important;}.has-light-blue-border-color{border-color: var(--wp--preset--color--light-blue) !important;}.has-dark-brown-border-color{border-color: var(--wp--preset--color--dark-brown) !important;}.has-medium-brown-border-color{border-color: var(--wp--preset--color--medium-brown) !important;}.has-dark-red-border-color{border-color: var(--wp--preset--color--dark-red) !important;}.has-bright-red-border-color{border-color: var(--wp--preset--color--bright-red) !important;}.has-yellow-border-color{border-color: var(--wp--preset--color--yellow) !important;}.has-vivid-cyan-blue-to-vivid-purple-gradient-background{background: var(--wp--preset--gradient--vivid-cyan-blue-to-vivid-purple) !important;}.has-light-green-cyan-to-vivid-green-cyan-gradient-background{background: var(--wp--preset--gradient--light-green-cyan-to-vivid-green-cyan) !important;}.has-luminous-vivid-amber-to-luminous-vivid-orange-gradient-background{background: var(--wp--preset--gradient--luminous-vivid-amber-to-luminous-vivid-orange) !important;}.has-luminous-vivid-orange-to-vivid-red-gradient-background{background: var(--wp--preset--gradient--luminous-vivid-orange-to-vivid-red) !important;}.has-very-light-gray-to-cyan-bluish-gray-gradient-background{background: var(--wp--preset--gradient--very-light-gray-to-cyan-bluish-gray) !important;}.has-cool-to-warm-spectrum-gradient-background{background: var(--wp--preset--gradient--cool-to-warm-spectrum) !important;}.has-blush-light-purple-gradient-background{background: var(--wp--preset--gradient--blush-light-purple) !important;}.has-blush-bordeaux-gradient-background{background: var(--wp--preset--gradient--blush-bordeaux) !important;}.has-luminous-dusk-gradient-background{background: var(--wp--preset--gradient--luminous-dusk) !important;}.has-pale-ocean-gradient-background{background: var(--wp--preset--gradient--pale-ocean) !important;}.has-electric-grass-gradient-background{background: var(--wp--preset--gradient--electric-grass) !important;}.has-midnight-gradient-background{background: var(--wp--preset--gradient--midnight) !important;}.has-small-font-size{font-size: var(--wp--preset--font-size--small) !important;}.has-medium-font-size{font-size: var(--wp--preset--font-size--medium) !important;}.has-large-font-size{font-size: var(--wp--preset--font-size--large) !important;}.has-x-large-font-size{font-size: var(--wp--preset--font-size--x-large) !important;}.has-albert-sans-font-family{font-family: var(--wp--preset--font-family--albert-sans) !important;}.has-alegreya-font-family{font-family: var(--wp--preset--font-family--alegreya) !important;}.has-arvo-font-family{font-family: var(--wp--preset--font-family--arvo) !important;}.has-bodoni-moda-font-family{font-family: var(--wp--preset--font-family--bodoni-moda) !important;}.has-bricolage-grotesque-font-family{font-family: var(--wp--preset--font-family--bricolage-grotesque) !important;}.has-cabin-font-family{font-family: var(--wp--preset--font-family--cabin) !important;}.has-chivo-font-family{font-family: var(--wp--preset--font-family--chivo) !important;}.has-commissioner-font-family{font-family: var(--wp--preset--font-family--commissioner) !important;}.has-cormorant-font-family{font-family: var(--wp--preset--font-family--cormorant) !important;}.has-courier-prime-font-family{font-family: var(--wp--preset--font-family--courier-prime) !important;}.has-crimson-pro-font-family{font-family: var(--wp--preset--font-family--crimson-pro) !important;}.has-dm-mono-font-family{font-family: var(--wp--preset--font-family--dm-mono) !important;}.has-dm-sans-font-family{font-family: var(--wp--preset--font-family--dm-sans) !important;}.has-dm-serif-display-font-family{font-family: var(--wp--preset--font-family--dm-serif-display) !important;}.has-domine-font-family{font-family: var(--wp--preset--font-family--domine) !important;}.has-eb-garamond-font-family{font-family: var(--wp--preset--font-family--eb-garamond) !important;}.has-epilogue-font-family{font-family: var(--wp--preset--font-family--epilogue) !important;}.has-fahkwang-font-family{font-family: var(--wp--preset--font-family--fahkwang) !important;}.has-figtree-font-family{font-family: var(--wp--preset--font-family--figtree) !important;}.has-fira-sans-font-family{font-family: var(--wp--preset--font-family--fira-sans) !important;}.has-fjalla-one-font-family{font-family: var(--wp--preset--font-family--fjalla-one) !important;}.has-fraunces-font-family{font-family: var(--wp--preset--font-family--fraunces) !important;}.has-gabarito-font-family{font-family: var(--wp--preset--font-family--gabarito) !important;}.has-ibm-plex-mono-font-family{font-family: var(--wp--preset--font-family--ibm-plex-mono) !important;}.has-ibm-plex-sans-font-family{font-family: var(--wp--preset--font-family--ibm-plex-sans) !important;}.has-ibarra-real-nova-font-family{font-family: var(--wp--preset--font-family--ibarra-real-nova) !important;}.has-instrument-serif-font-family{font-family: var(--wp--preset--font-family--instrument-serif) !important;}.has-inter-font-family{font-family: var(--wp--preset--font-family--inter) !important;}.has-josefin-sans-font-family{font-family: var(--wp--preset--font-family--josefin-sans) !important;}.has-jost-font-family{font-family: var(--wp--preset--font-family--jost) !important;}.has-libre-baskerville-font-family{font-family: var(--wp--preset--font-family--libre-baskerville) !important;}.has-libre-franklin-font-family{font-family: var(--wp--preset--font-family--libre-franklin) !important;}.has-literata-font-family{font-family: var(--wp--preset--font-family--literata) !important;}.has-lora-font-family{font-family: var(--wp--preset--font-family--lora) !important;}.has-merriweather-font-family{font-family: var(--wp--preset--font-family--merriweather) !important;}.has-montserrat-font-family{font-family: var(--wp--preset--font-family--montserrat) !important;}.has-newsreader-font-family{font-family: var(--wp--preset--font-family--newsreader) !important;}.has-noto-sans-mono-font-family{font-family: var(--wp--preset--font-family--noto-sans-mono) !important;}.has-nunito-font-family{font-family: var(--wp--preset--font-family--nunito) !important;}.has-open-sans-font-family{font-family: var(--wp--preset--font-family--open-sans) !important;}.has-overpass-font-family{font-family: var(--wp--preset--font-family--overpass) !important;}.has-pt-serif-font-family{font-family: var(--wp--preset--font-family--pt-serif) !important;}.has-petrona-font-family{font-family: var(--wp--preset--font-family--petrona) !important;}.has-piazzolla-font-family{font-family: var(--wp--preset--font-family--piazzolla) !important;}.has-playfair-display-font-family{font-family: var(--wp--preset--font-family--playfair-display) !important;}.has-plus-jakarta-sans-font-family{font-family: var(--wp--preset--font-family--plus-jakarta-sans) !important;}.has-poppins-font-family{font-family: var(--wp--preset--font-family--poppins) !important;}.has-raleway-font-family{font-family: var(--wp--preset--font-family--raleway) !important;}.has-roboto-font-family{font-family: var(--wp--preset--font-family--roboto) !important;}.has-roboto-slab-font-family{font-family: var(--wp--preset--font-family--roboto-slab) !important;}.has-rubik-font-family{font-family: var(--wp--preset--font-family--rubik) !important;}.has-rufina-font-family{font-family: var(--wp--preset--font-family--rufina) !important;}.has-sora-font-family{font-family: var(--wp--preset--font-family--sora) !important;}.has-source-sans-3-font-family{font-family: var(--wp--preset--font-family--source-sans-3) !important;}.has-source-serif-4-font-family{font-family: var(--wp--preset--font-family--source-serif-4) !important;}.has-space-mono-font-family{font-family: var(--wp--preset--font-family--space-mono) !important;}.has-syne-font-family{font-family: var(--wp--preset--font-family--syne) !important;}.has-texturina-font-family{font-family: var(--wp--preset--font-family--texturina) !important;}.has-urbanist-font-family{font-family: var(--wp--preset--font-family--urbanist) !important;}.has-work-sans-font-family{font-family: var(--wp--preset--font-family--work-sans) !important;}
/*# sourceURL=global-styles-inline-css */
&lt;/style&gt;

&lt;link crossorigin="anonymous" rel="stylesheet" id="all-css-14-1" href="/wp-content/mu-plugins/jetpack-mu-wpcom-plugin/moon/jetpack_vendor/automattic/jetpack-mu-wpcom/src/build/verbum-comments/verbum-comments.css?m=1785895867i&amp;amp;cssminify=yes" type="text/css" media="all"&gt;
&lt;link rel="stylesheet" id="verbum-gutenberg-css-css" href="https://widgets.wp.com/verbum-block-editor/block-editor.css?ver=1771405207" media="all"&gt;
&lt;link crossorigin="anonymous" rel="stylesheet" id="all-css-16-1" href="/_static/??-eJyNjbEOgzAQQ3+o1KBK0AXxKVU5nSCQXKLeRcDfN6o6dGDoZlvPNrZUURRjMYRcJZ8nJ4qFLT1p/XqEGAUPJ4SJhV+uNPRcXkn1gp9RmzmwIuURtpXgULcbs0Dt8Pw/XkCMPtL6uRhC33Rd09bt7V4vb1EVSjI=&amp;amp;cssminify=yes" type="text/css" media="all"&gt;
&lt;link crossorigin="anonymous" rel="stylesheet" id="all-css-22-1" href="/_static/??-eJx9y0EOwjAMRNELYUxEK7FBnKWNTAhK7Kh2lPb2pGyADbv5Iz1sBbywERvagzIpljqjtX5sGlcjYvSqqLYlgla85GPvA37BXKGkGiIrLjQnCX2Gt/rkPxRIIImfLAr/BNzTFJed3vLVjW4YT2fnLs8X8DhDqQ==&amp;amp;cssminify=yes" type="text/css" media="all"&gt;
&lt;style id="jetpack-global-styles-frontend-style-inline-css"&gt;
:root { --font-headings: unset; --font-base: unset; --font-headings-default: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif; --font-base-default: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;}
/*# sourceURL=jetpack-global-styles-frontend-style-inline-css */
&lt;/style&gt;
&lt;link crossorigin="anonymous" rel="stylesheet" id="all-css-24-1" href="/_static/??-eJyNjcEKAjEMRH/ImhVlqwfxU6TbhrZrmhTTIv69u+JFvHgZ5sHwBh7VeOGG3KB0U6nHzAoztur87cNQRNYInVBBk7tjcCE83zVz3HrVDfxvumb2MPVMAVR8dmRIougX/DhbwrK8pwNEksnROriU884e9+PJDnaYXxwFS20=&amp;amp;cssminify=yes" type="text/css" media="all"&gt;
&lt;script id="jetpack_related-posts-js-extra"&gt;
var related_posts_js_options = {"post_heading":"h4"};
//# sourceURL=jetpack_related-posts-js-extra
&lt;/script&gt;
&lt;script id="wpcom-actionbar-placeholder-js-extra"&gt;
var actionbardata = {"siteID":"15031761","postID":"4719","siteURL":"https://codemanship.wordpress.com","xhrURL":"https://codemanship.wordpress.com/wp-admin/admin-ajax.php","nonce":"319d689d5a","isLoggedIn":"","statusMessage":"","subsEmailDefault":"instantly","proxyScriptUrl":"https://s0.wp.com/wp-content/js/wpcom-proxy-request.js?m=1513050504i&amp;amp;ver=20211021","shortlink":"https://wp.me/p114rL-1e7","i18n":{"followedText":"New posts from this site will now appear in your \u003Ca href=\"https://wordpress.com/reader\"\u003EReader\u003C/a\u003E","foldBar":"Collapse this bar","unfoldBar":"Expand this bar","shortLinkCopied":"Shortlink copied to clipboard."}};
//# sourceURL=wpcom-actionbar-placeholder-js-extra
&lt;/script&gt;
&lt;script id="jetpack-mu-wpcom-settings-js-before"&gt;
var JETPACK_MU_WPCOM_SETTINGS = {"assetsUrl":"https://s0.wp.com/wp-content/mu-plugins/jetpack-mu-wpcom-plugin/moon/jetpack_vendor/automattic/jetpack-mu-wpcom/src/build/"};
//# sourceURL=jetpack-mu-wpcom-settings-js-before
&lt;/script&gt;
&lt;script crossorigin="anonymous" type="text/javascript" src="/_static/??-eJxdjEsOwjAMRC9E6lIpsEIcBfVj0YTYsWpHbW/fILEAlm9m3sAqbsxsyAZUnKTyDKwQ0aQfXx8GypnhEXiEoYQ0wYKpN5ycZDX9pYYCN1FP8HUc6yaZkyVv+39nMxIqSBnA1hrsGjZD5Lc0GyVfhTvdzlfv2/bSdT4e2plCCA=="&gt;&lt;/script&gt;
&lt;script id="rlt-proxy-js-after"&gt;
	rltInitialize( {"token":null,"iframeOrigins":["https:\/\/widgets.wp.com"]} );
//# sourceURL=rlt-proxy-js-after
&lt;/script&gt;
&lt;link rel="EditURI" type="application/rsd+xml" title="RSD" href="https://codemanship.wordpress.com/xmlrpc.php?rsd"&gt;
&lt;meta name="generator" content="WordPress.com"&gt;
&lt;link rel="canonical" href="https://codemanship.wordpress.com/2026/08/12/ai-software-development-what-does-the-data-say/"&gt;
&lt;link rel="shortlink" href="https://wp.me/p114rL-1e7"&gt;
&lt;link rel="alternate" type="application/json+oembed" href="https://public-api.wordpress.com/oembed/?format=json&amp;amp;url=https%3A%2F%2Fcodemanship.wordpress.com%2F2026%2F08%2F12%2Fai-software-development-what-does-the-data-say%2F&amp;amp;for=wpcom-auto-discovery"&gt;&lt;link rel="alternate" type="application/xml+oembed" href="https://public-api.wordpress.com/oembed/?format=xml&amp;amp;url=https%3A%2F%2Fcodemanship.wordpress.com%2F2026%2F08%2F12%2Fai-software-development-what-does-the-data-say%2F&amp;amp;for=wpcom-auto-discovery"&gt;
&lt;!-- Jetpack Open Graph Tags --&gt;
&lt;meta property="og:type" content="article"&gt;
&lt;meta property="og:title" content="AI Software Development – What Does The Data Say?"&gt;
&lt;meta property="og:url" content="https://codemanship.wordpress.com/2026/08/12/ai-software-development-what-does-the-data-say/"&gt;
&lt;meta property="og:description" content="I’m currently pulling together a bunch of sources – that are mostly recent – on the topic of LLMs and their use in software development. Some are peer-reviewed studies. Some are i…"&gt;
&lt;meta property="article:published_time" content="2026-08-12T17:41:50+00:00"&gt;
&lt;meta property="article:modified_time" content="2026-08-12T17:46:26+00:00"&gt;
&lt;meta property="og:site_name" content="Codemanship's Blog"&gt;
&lt;meta property="og:image" content="https://i0.wp.com/codemanship.wordpress.com/wp-content/uploads/2026/08/evidence.png?fit=1200%2C675&amp;amp;ssl=1"&gt;
&lt;meta property="og:image:width" content="1200"&gt;
&lt;meta property="og:image:height" content="675"&gt;
&lt;meta property="og:image:alt" content=""&gt;
&lt;meta property="og:locale" content="en_US"&gt;
&lt;meta property="fb:app_id" content="249643311490"&gt;
&lt;meta property="article:publisher" content="https://www.facebook.com/WordPresscom"&gt;
&lt;meta name="twitter:text:title" content="AI Software Development – What Does The Data&amp;nbsp;Say?"&gt;
&lt;meta name="twitter:image" content="https://i0.wp.com/codemanship.wordpress.com/wp-content/uploads/2026/08/evidence.png?fit=1200%2C675&amp;amp;ssl=1&amp;amp;w=640"&gt;
&lt;meta name="twitter:card" content="summary_large_image"&gt;

&lt;!-- End Jetpack Open Graph Tags --&gt;
&lt;link rel="openid.server" href="https://codemanship.wordpress.com/?openidserver=1"&gt;
&lt;link rel="openid.delegate" href="https://codemanship.wordpress.com/"&gt;
&lt;link rel="search" type="application/opensearchdescription+xml" href="https://codemanship.wordpress.com/osd.xml" title="Codemanship's Blog"&gt;
&lt;link rel="search" type="application/opensearchdescription+xml" href="https://s1.wp.com/opensearch.xml" title="WordPress.com"&gt;
		&lt;style type="text/css"&gt;
			.recentcomments a {
				display: inline !important;
				padding: 0 !important;
				margin: 0 !important;
			}

			table.recentcommentsavatartop img.avatar, table.recentcommentsavatarend img.avatar {
				border: 0px;
				margin: 0;
			}

			table.recentcommentsavatartop a, table.recentcommentsavatarend a {
				border: 0px !important;
				background-color: transparent !important;
			}

			td.recentcommentsavatarend, td.recentcommentsavatartop {
				padding: 0px 0px 1px 0px;
				margin: 0px;
			}

			td.recentcommentstextend {
				border: none !important;
				padding: 0px 0px 2px 10px;
			}

			.rtl td.recentcommentstextend {
				padding: 0px 10px 2px 0px;
			}

			td.recentcommentstexttop {
				border: none;
				padding: 0px 0px 0px 10px;
			}

			.rtl td.recentcommentstexttop {
				padding: 0px 10px 0px 0px;
			}
		&lt;/style&gt;
		&lt;meta name="description" content="I'm currently pulling together a bunch of sources - that are mostly recent - on the topic of LLMs and their use in software development. Some are peer-reviewed studies. Some are industry studies that haven't been peer-reviewed. One is statistical physics. Expect more from that angle. Wanna' know the limits of a technology? Ask a…"&gt;
&lt;link rel="icon" href="https://codemanship.wordpress.com/wp-content/uploads/2017/08/cropped-codemanship3_twitter_avatar.jpg?w=32" sizes="32x32"&gt;
&lt;link rel="icon" href="https://codemanship.wordpress.com/wp-content/uploads/2017/08/cropped-codemanship3_twitter_avatar.jpg?w=192" sizes="192x192"&gt;
&lt;link rel="apple-touch-icon" href="https://codemanship.wordpress.com/wp-content/uploads/2017/08/cropped-codemanship3_twitter_avatar.jpg?w=180"&gt;
&lt;meta name="msapplication-TileImage" content="https://codemanship.wordpress.com/wp-content/uploads/2017/08/cropped-codemanship3_twitter_avatar.jpg?w=270"&gt;
&lt;style id="jetpack-block-subscriptions-inline-css"&gt;
.is-style-compact .is-not-subscriber :is(.wp-block-button__link,.wp-block-jetpack-subscriptions__button){border-end-start-radius:0!important;border-start-start-radius:0!important;margin-inline-start:0!important}.is-style-compact .is-not-subscriber .components-text-control__input,.is-style-compact .is-not-subscriber p#subscribe-email input[type=email]{border-end-end-radius:0!important;border-start-end-radius:0!important}.is-style-compact:not(.wp-block-jetpack-subscriptions__use-newline) .components-text-control__input{border-inline-end-width:0!important}.wp-block-jetpack-subscriptions.wp-block-jetpack-subscriptions__supports-newline .wp-block-jetpack-subscriptions__form-container{display:flex;flex-direction:column}.wp-block-jetpack-subscriptions.wp-block-jetpack-subscriptions__supports-newline:not(.wp-block-jetpack-subscriptions__use-newline) .is-not-subscriber .wp-block-jetpack-subscriptions__form-elements{align-items:flex-start;display:flex}.wp-block-jetpack-subscriptions.wp-block-jetpack-subscriptions__supports-newline:not(.wp-block-jetpack-subscriptions__use-newline) p#subscribe-submit{display:flex;justify-content:center}.wp-block-jetpack-subscriptions.wp-block-jetpack-subscriptions__supports-newline .wp-block-jetpack-subscriptions__form .wp-block-jetpack-subscriptions__button,.wp-block-jetpack-subscriptions.wp-block-jetpack-subscriptions__supports-newline .wp-block-jetpack-subscriptions__form .wp-block-jetpack-subscriptions__textfield .components-text-control__input,.wp-block-jetpack-subscriptions.wp-block-jetpack-subscriptions__supports-newline .wp-block-jetpack-subscriptions__form button,.wp-block-jetpack-subscriptions.wp-block-jetpack-subscriptions__supports-newline .wp-block-jetpack-subscriptions__form input[type=email],.wp-block-jetpack-subscriptions.wp-block-jetpack-subscriptions__supports-newline form .wp-block-jetpack-subscriptions__button,.wp-block-jetpack-subscriptions.wp-block-jetpack-subscriptions__supports-newline form .wp-block-jetpack-subscriptions__textfield .components-text-control__input,.wp-block-jetpack-subscriptions.wp-block-jetpack-subscriptions__supports-newline form button,.wp-block-jetpack-subscriptions.wp-block-jetpack-subscriptions__supports-newline form input[type=email]{box-sizing:border-box;cursor:pointer;line-height:1.3;min-width:auto!important;white-space:nowrap!important}.wp-block-jetpack-subscriptions.wp-block-jetpack-subscriptions__supports-newline .wp-block-jetpack-subscriptions__form input[type=email]::placeholder,.wp-block-jetpack-subscriptions.wp-block-jetpack-subscriptions__supports-newline .wp-block-jetpack-subscriptions__form input[type=email]:disabled,.wp-block-jetpack-subscriptions.wp-block-jetpack-subscriptions__supports-newline form input[type=email]::placeholder,.wp-block-jetpack-subscriptions.wp-block-jetpack-subscriptions__supports-newline form input[type=email]:disabled{color:currentColor;opacity:.5}.wp-block-jetpack-subscriptions.wp-block-jetpack-subscriptions__supports-newline .wp-block-jetpack-subscriptions__form .wp-block-jetpack-subscriptions__button,.wp-block-jetpack-subscriptions.wp-block-jetpack-subscriptions__supports-newline .wp-block-jetpack-subscriptions__form button,.wp-block-jetpack-subscriptions.wp-block-jetpack-subscriptions__supports-newline form .wp-block-jetpack-subscriptions__button,.wp-block-jetpack-subscriptions.wp-block-jetpack-subscriptions__supports-newline form button{border-color:#0000;border-style:solid}.wp-block-jetpack-subscriptions.wp-block-jetpack-subscriptions__supports-newline .wp-block-jetpack-subscriptions__form .wp-block-jetpack-subscriptions__textfield,.wp-block-jetpack-subscriptions.wp-block-jetpack-subscriptions__supports-newline .wp-block-jetpack-subscriptions__form p#subscribe-email,.wp-block-jetpack-subscriptions.wp-block-jetpack-subscriptions__supports-newline form .wp-block-jetpack-subscriptions__textfield,.wp-block-jetpack-subscriptions.wp-block-jetpack-subscriptions__supports-newline form p#subscribe-email{background:#0000;flex-grow:1}.wp-block-jetpack-subscriptions.wp-block-jetpack-subscriptions__supports-newline .wp-block-jetpack-subscriptions__form .wp-block-jetpack-subscriptions__textfield .components-base-control__field,.wp-block-jetpack-subscriptions.wp-block-jetpack-subscriptions__supports-newline .wp-block-jetpack-subscriptions__form .wp-block-jetpack-subscriptions__textfield .components-text-control__input,.wp-block-jetpack-subscriptions.wp-block-jetpack-subscriptions__supports-newline .wp-block-jetpack-subscriptions__form .wp-block-jetpack-subscriptions__textfield input[type=email],.wp-block-jetpack-subscriptions.wp-block-jetpack-subscriptions__supports-newline .wp-block-jetpack-subscriptions__form p#subscribe-email .components-base-control__field,.wp-block-jetpack-subscriptions.wp-block-jetpack-subscriptions__supports-newline .wp-block-jetpack-subscriptions__form p#subscribe-email .components-text-control__input,.wp-block-jetpack-subscriptions.wp-block-jetpack-subscriptions__supports-newline .wp-block-jetpack-subscriptions__form p#subscribe-email input[type=email],.wp-block-jetpack-subscriptions.wp-block-jetpack-subscriptions__supports-newline form .wp-block-jetpack-subscriptions__textfield .components-base-control__field,.wp-block-jetpack-subscriptions.wp-block-jetpack-subscriptions__supports-newline form .wp-block-jetpack-subscriptions__textfield .components-text-control__input,.wp-block-jetpack-subscriptions.wp-block-jetpack-subscriptions__supports-newline form .wp-block-jetpack-subscriptions__textfield input[type=email],.wp-block-jetpack-subscriptions.wp-block-jetpack-subscriptions__supports-newline form p#subscribe-email .components-base-control__field,.wp-block-jetpack-subscriptions.wp-block-jetpack-subscriptions__supports-newline form p#subscribe-email .components-text-control__input,.wp-block-jetpack-subscriptions.wp-block-jetpack-subscriptions__supports-newline form p#subscribe-email input[type=email]{height:auto;margin:0;width:100%}.wp-block-jetpack-subscriptions.wp-block-jetpack-subscriptions__supports-newline .wp-block-jetpack-subscriptions__form p#subscribe-email,.wp-block-jetpack-subscriptions.wp-block-jetpack-subscriptions__supports-newline .wp-block-jetpack-subscriptions__form p#subscribe-submit,.wp-block-jetpack-subscriptions.wp-block-jetpack-subscriptions__supports-newline form p#subscribe-email,.wp-block-jetpack-subscriptions.wp-block-jetpack-subscriptions__supports-newline form p#subscribe-submit{line-height:0;margin:0;padding:0}.wp-block-jetpack-subscriptions.wp-block-jetpack-subscriptions__supports-newline.wp-block-jetpack-subscriptions__show-subs .wp-block-jetpack-subscriptions__subscount{font-size:16px;margin:8px 0;text-align:end}.wp-block-jetpack-subscriptions.wp-block-jetpack-subscriptions__supports-newline.wp-block-jetpack-subscriptions__use-newline .wp-block-jetpack-subscriptions__form-elements{display:block}.wp-block-jetpack-subscriptions.wp-block-jetpack-subscriptions__supports-newline.wp-block-jetpack-subscriptions__use-newline .wp-block-jetpack-subscriptions__button,.wp-block-jetpack-subscriptions.wp-block-jetpack-subscriptions__supports-newline.wp-block-jetpack-subscriptions__use-newline button{display:inline-block;max-width:100%}.wp-block-jetpack-subscriptions.wp-block-jetpack-subscriptions__supports-newline.wp-block-jetpack-subscriptions__use-newline .wp-block-jetpack-subscriptions__subscount{text-align:start}#subscribe-submit.is-link{text-align:center;width:auto!important}#subscribe-submit.is-link a{margin-left:0!important;margin-top:0!important;width:auto!important}@keyframes jetpack-memberships_button__spinner-animation{to{transform:rotate(1turn)}}.jetpack-memberships-spinner{display:none;height:1em;margin:0 0 0 5px;width:1em}.jetpack-memberships-spinner svg{height:100%;margin-bottom:-2px;width:100%}.jetpack-memberships-spinner-rotating{animation:jetpack-memberships_button__spinner-animation .75s linear infinite;transform-origin:center}.is-loading .jetpack-memberships-spinner{display:inline-block}body.jetpack-memberships-modal-open{overflow:hidden}dialog.jetpack-memberships-modal{opacity:1}dialog.jetpack-memberships-modal,dialog.jetpack-memberships-modal iframe{background:#0000;border:0;bottom:0;box-shadow:none;height:100%;left:0;margin:0;padding:0;position:fixed;right:0;top:0;width:100%}dialog.jetpack-memberships-modal::backdrop{background-color:#000;opacity:.7;transition:opacity .2s ease-out}dialog.jetpack-memberships-modal.is-loading,dialog.jetpack-memberships-modal.is-loading::backdrop{opacity:0}
/*# sourceURL=/wp-content/mu-plugins/jetpack-plugin/moon/_inc/blocks/subscriptions/view.css?minify=false */
&lt;/style&gt;&lt;link rel="stylesheet" href="https://fonts-api.wp.com/css?family=Alegreya+Sans:r%7CAlegreya+Sans:r,i,b,bi&amp;amp;subset=latin,latin-ext,latin,latin-ext" media="all"&gt;

&lt;script src="/wp-includes/js/wp-emoji-release.min.js?m=1783090810i&amp;amp;ver=7.1-alpha-62686" defer=""&gt;&lt;/script&gt;&lt;link rel="stylesheet" id="gravatar-card-css" href="https://0.gravatar.com/js/hovercards/hovercards.min.css?ver=202633d1133547e8a1f2801609f51cef12522abe7f6647d869e9fbc974fe356a37e613"&gt;&lt;link href="/wp-content/mu-plugins/actionbar/actionbar.css?v=20250116" type="text/css" rel="stylesheet"&gt;&lt;/head&gt;

&lt;body class="wp-singular post-template-default single single-post postid-4719 single-format-standard wp-embed-responsive wp-theme-pubtwentysixteen customizer-styles-applied jetpack-reblog-enabled"&gt;
&lt;div id="page" class="site"&gt;
	&lt;div class="site-inner"&gt;
		&lt;a class="skip-link screen-reader-text" href="#content"&gt;
			Skip to content		&lt;/a&gt;

		&lt;header id="masthead" class="site-header"&gt;
			&lt;div class="site-header-main"&gt;
				&lt;div class="site-branding"&gt;
					&lt;a href="https://codemanship.wordpress.com/" class="site-logo-link" rel="home" itemprop="url"&gt;&lt;/a&gt;
											&lt;p class="site-title"&gt;&lt;a href="https://codemanship.wordpress.com/" rel="home"&gt;Codemanship's Blog&lt;/a&gt;&lt;/p&gt;
												&lt;p class="site-description"&gt;Musings And Mutterings By Jason Gorman&lt;/p&gt;
									&lt;/div&gt;&lt;!-- .site-branding --&gt;

									&lt;button id="menu-toggle" class="menu-toggle"&gt;Menu&lt;/button&gt;

					&lt;div id="site-header-menu" class="site-header-menu"&gt;
													&lt;nav id="site-navigation" class="main-navigation" aria-label="Primary Menu"&gt;
								&lt;div class="menu-codemanship-container"&gt;&lt;ul id="menu-codemanship" class="primary-menu"&gt;&lt;li id="menu-item-65" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-home menu-item-65"&gt;&lt;a href="https://codemanship.wordpress.com"&gt;Home&lt;/a&gt;&lt;/li&gt;
&lt;li id="menu-item-66" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-66"&gt;&lt;a href="https://codemanship.wordpress.com/about/"&gt;About&lt;/a&gt;&lt;/li&gt;
&lt;li id="menu-item-67" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-67"&gt;&lt;a href="https://www.codemanship.co.uk"&gt;Training&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;							&lt;/nav&gt;&lt;!-- .main-navigation --&gt;
						
											&lt;/div&gt;&lt;!-- .site-header-menu --&gt;
							&lt;/div&gt;&lt;!-- .site-header-main --&gt;

											&lt;div class="header-image"&gt;
					&lt;a href="https://codemanship.wordpress.com/" rel="home"&gt;
						&lt;img src="https://codemanship.wordpress.com/wp-content/uploads/2017/08/cropped-codemanship3_wp_header1-1.jpg" srcset="" sizes="" width="1200" height="280" alt="Codemanship's Blog"&gt;
					&lt;/a&gt;
				&lt;/div&gt;&lt;!-- .header-image --&gt;
					&lt;/header&gt;&lt;!-- .site-header --&gt;

		&lt;div id="content" class="site-content"&gt;

&lt;div id="primary" class="content-area"&gt;
	&lt;main id="main" class="site-main"&gt;
		
&lt;article id="post-4719" class="post-4719 post type-post status-publish format-standard has-post-thumbnail hentry category-a-i"&gt;
	&lt;header class="entry-header"&gt;
		&lt;h1 class="entry-title"&gt;AI Software Development – What Does The Data&amp;nbsp;Say?&lt;/h1&gt;	&lt;/header&gt;&lt;!-- .entry-header --&gt;

	
	
		&lt;div class="post-thumbnail"&gt;
			&lt;img width="1200" height="675" src="https://codemanship.wordpress.com/wp-content/uploads/2026/08/evidence.png?w=1200" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="" decoding="async" srcset="https://codemanship.wordpress.com/wp-content/uploads/2026/08/evidence.png?w=1200 1200w, https://codemanship.wordpress.com/wp-content/uploads/2026/08/evidence.png?w=150 150w, https://codemanship.wordpress.com/wp-content/uploads/2026/08/evidence.png?w=300 300w, https://codemanship.wordpress.com/wp-content/uploads/2026/08/evidence.png?w=768 768w, https://codemanship.wordpress.com/wp-content/uploads/2026/08/evidence.png?w=1024 1024w, https://codemanship.wordpress.com/wp-content/uploads/2026/08/evidence.png?w=1440 1440w, https://codemanship.wordpress.com/wp-content/uploads/2026/08/evidence.png 1672w" sizes="(max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 984px) 60vw, (max-width: 1362px) 62vw, 840px" data-attachment-id="4725" data-permalink="https://codemanship.wordpress.com/2026/08/12/ai-software-development-what-does-the-data-say/evidence/" data-orig-file="https://codemanship.wordpress.com/wp-content/uploads/2026/08/evidence.png" data-orig-size="1672,941" data-comments-opened="1" data-image-meta="{&amp;quot;aperture&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;credit&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;camera&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;caption&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;created_timestamp&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;copyright&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;focal_length&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;iso&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;shutter_speed&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;title&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;orientation&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;alt&amp;quot;:&amp;quot;&amp;quot;}" data-image-title="evidence" data-image-description="" data-image-caption="" data-large-file="https://codemanship.wordpress.com/wp-content/uploads/2026/08/evidence.png?w=840"&gt;	&lt;/div&gt;&lt;!-- .post-thumbnail --&gt;

	
	&lt;div class="entry-content"&gt;
		
&lt;p class="wp-block-paragraph"&gt;I’m currently pulling together a bunch of sources – that are mostly recent – on the topic of LLMs and their use in software development.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Some are peer-reviewed studies. Some are industry studies that haven’t been peer-reviewed.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;One is statistical physics. Expect more from that angle. Wanna’ know the limits of a technology? Ask a physicist.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;One is just a blog post, but very useful information about the effect of context size.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Most are corroborated by personal experiments and also observations on teams. As time goes on and more data comes in, my picture comes more into focus.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Code Evolution &amp;amp; Long-Horizon Agentic Workflows&lt;/strong&gt;&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;SWE-CI: Evaluating Agent Capabilities in Maintaining Codebases via Continuous Integration&lt;br&gt;&lt;a href="https://arxiv.org/abs/2603.03823"&gt;https://arxiv.org/abs/2603.03823&lt;/a&gt;&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;SlopCodeBench: Benchmarking How Coding Agents Degrade Over Long-Horizon Iterative Tasks&lt;br&gt;&lt;a href="https://arxiv.org/html/2603.24755v1"&gt;https://arxiv.org/html/2603.24755v1&lt;/a&gt;&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;SWE-Milestone: Evaluating AI Agents on Continuous Software Evolution&lt;br&gt;&lt;a href="https://arxiv.org/abs/2603.13428"&gt;https://arxiv.org/abs/2603.13428&lt;/a&gt;&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Context Engineering&lt;/strong&gt;&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Context Is What You Need: The Maximum Effective Context Window for Real World Limits of LLMs&lt;br&gt;&lt;a href="https://arxiv.org/abs/2509.21361"&gt;https://arxiv.org/abs/2509.21361&lt;/a&gt;&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Beyond RAG vs. Long-Context: Learning Distraction-Aware Retrieval for Efficient Knowledge Grounding&lt;br&gt;&lt;a href="https://arxiv.org/abs/2509.21865"&gt;https://arxiv.org/abs/2509.21865&lt;/a&gt;&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Evaluating AGENTS.md: Are Repository-Level Context Files Helpful for Coding Agents?&lt;br&gt;&lt;a href="https://arxiv.org/abs/2602.11988"&gt;https://arxiv.org/abs/2602.11988&lt;/a&gt;&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;(blog post – informational, not peer-reviewed research)&lt;br&gt;The Hidden Science Behind LLM Token Limits (And How Million-Token Models Actually Work)&lt;br&gt;&lt;a href="https://www.ashisharora.ai/post/the-hidden-science-behind-llm-token-limits-and-how-million-token-models-actually-work"&gt;https://www.ashisharora.ai/post/the-hidden-science-behind-llm-token-limits-and-how-million-token-models-actually-work&lt;/a&gt;&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Language models are not naysayers: An analysis of language models on negation benchmarks&lt;br&gt;&lt;a href="https://arxiv.org/abs/2602.11988"&gt;https://arxiv.org/abs/2602.11988&lt;/a&gt;&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Rethinking the Role of Demonstrations: What Makes In-Context Learning Work?&lt;br&gt;&lt;a href="https://aclanthology.org/2022.emnlp-main.759"&gt;https://aclanthology.org/2022.emnlp-main.759&lt;/a&gt;&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;STALE: Can LLM Agents Know When Their Memories Are No Longer Valid?&lt;br&gt;&lt;a href="https://arxiv.org/abs/2605.06527"&gt;https://arxiv.org/abs/2605.06527&lt;/a&gt;&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Task Matters: Knowledge Requirements Shape LLM Responses to&lt;br&gt;Context–Memory Conflict&lt;br&gt;&lt;a href="https://aclanthology.org/2026.findings-acl.202"&gt;https://aclanthology.org/2026.findings-acl.202&lt;/a&gt;&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;(I call these “dominant priors”, when information in the model overrides that provided in the context)&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Large-scale Industry Studies in Software Engineering&lt;/strong&gt;&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;What 28 million workflows reveal about AI coding’s biggest risk (CircleCI)&lt;br&gt;&lt;a href="https://www.linkedin.com/pulse/what-28-million-workflows-reveal-ai-codings-biggest-risk-circleci-j9syc/"&gt;https://www.linkedin.com/pulse/what-28-million-workflows-reveal-ai-codings-biggest-risk-circleci-j9syc/&lt;/a&gt;&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;The Acceleration Whiplash – AI Engineering Report 2026 (Faros)&lt;br&gt;&lt;a href="https://www.faros.ai/research/ai-acceleration-whiplash"&gt;https://www.faros.ai/research/ai-acceleration-whiplash&lt;/a&gt;&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;State of AI-assisted Software Development 2025 (DORA)&lt;br&gt;&lt;a href="https://dora.dev/research/2025/dora-report/"&gt;https://dora.dev/research/2025/dora-report/&lt;/a&gt;&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Psychology, Cognition &amp;amp; Learning&lt;/strong&gt;&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Super-intelligence or Superstition? Exploring Psychological Factors Influencing Belief in AI Predictions about Personal Behavior&lt;br&gt;&lt;a href="https://arxiv.org/html/2408.06602v3"&gt;https://arxiv.org/html/2408.06602v3&lt;/a&gt;&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;The Impact of Generative AI on Critical Thinking: Self-Reported Reductions in Cognitive Effort and Confidence Effects From a Survey of Knowledge Workers&lt;br&gt;&lt;a href="https://arxiv.org/html/2408.06602v3"&gt;https://arxiv.org/html/2408.06602v3&lt;/a&gt;&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Experimental evidence of the effects of large language models versus web search on depth of learning&lt;br&gt;&lt;a href="https://arxiv.org/html/2408.06602v3"&gt;https://arxiv.org/html/2408.06602v3&lt;/a&gt;&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;At What Cost? Software Developers’ Well-Being in the Age of GenAI&lt;br&gt;&lt;a href="https://ourarchive.otago.ac.nz/esploro/outputs/preprint/At-What-Cost-Software-Developers-Well-Being/9926870122801891"&gt;https://ourarchive.otago.ac.nz/esploro/outputs/preprint/At-What-Cost-Software-Developers-Well-Being/9926870122801891&lt;/a&gt;&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Limits of LLMs &amp;amp; Deep Learning&lt;/strong&gt;&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;The wall confronting large language models – (statistical mechanics study)&lt;br&gt;&lt;a href="https://arxiv.org/abs/2507.19703"&gt;https://arxiv.org/abs/2507.19703&lt;/a&gt;&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Learning long-term dependencies with gradient descent is difficult&lt;br&gt;&lt;a href="https://pubmed.ncbi.nlm.nih.gov/18267787/"&gt;https://pubmed.ncbi.nlm.nih.gov/18267787/&lt;/a&gt;&lt;br&gt;(Why deep neural networks can’t see the bigger picture, at any scale of model)&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;&lt;em&gt;What are the implications for teams using this technology? If you’re interested in a hype-free, evidence-based take about why the technical practices of Agile Software Development are so closely aligned with AI-assisted and agentic software engineering, join me on October 6th at 18:45 BST&lt;/em&gt;.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;&lt;em&gt;Register: &lt;a href="https://www.tickettailor.com/events/codemanship/2324138"&gt;https://www.tickettailor.com/events/codemanship/2324138&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;div id="jp-post-flair" class="sharedaddy sd-like-enabled sd-sharing-enabled"&gt;&lt;div class="sharedaddy sd-sharing-enabled"&gt;&lt;div class="robots-nocontent sd-block sd-social sd-social-icon-text sd-sharing"&gt;&lt;h3 class="sd-title"&gt;Share this:&lt;/h3&gt;&lt;div class="sd-content"&gt;&lt;ul&gt;&lt;li class="share-twitter"&gt;&lt;a rel="nofollow noopener noreferrer" data-shared="sharing-twitter-4719" class="share-twitter sd-button share-icon" href="https://codemanship.wordpress.com/2026/08/12/ai-software-development-what-does-the-data-say/?share=twitter" target="_blank" aria-labelledby="sharing-twitter-4719"&gt;
				&lt;span id="sharing-twitter-4719" hidden=""&gt;Share on X (Opens in new window)&lt;/span&gt;
				&lt;span&gt;X&lt;/span&gt;
			&lt;/a&gt;&lt;/li&gt;&lt;li class="share-facebook"&gt;&lt;a rel="nofollow noopener noreferrer" data-shared="sharing-facebook-4719" class="share-facebook sd-button share-icon" href="https://codemanship.wordpress.com/2026/08/12/ai-software-development-what-does-the-data-say/?share=facebook" target="_blank" aria-labelledby="sharing-facebook-4719"&gt;
				&lt;span id="sharing-facebook-4719" hidden=""&gt;Share on Facebook (Opens in new window)&lt;/span&gt;
				&lt;span&gt;Facebook&lt;/span&gt;
			&lt;/a&gt;&lt;/li&gt;&lt;li class="share-linkedin"&gt;&lt;a rel="nofollow noopener noreferrer" data-shared="sharing-linkedin-4719" class="share-linkedin sd-button share-icon" href="https://codemanship.wordpress.com/2026/08/12/ai-software-development-what-does-the-data-say/?share=linkedin" target="_blank" aria-labelledby="sharing-linkedin-4719"&gt;
				&lt;span id="sharing-linkedin-4719" hidden=""&gt;Share on LinkedIn (Opens in new window)&lt;/span&gt;
				&lt;span&gt;LinkedIn&lt;/span&gt;
			&lt;/a&gt;&lt;/li&gt;&lt;li class="share-reddit"&gt;&lt;a rel="nofollow noopener noreferrer" data-shared="sharing-reddit-4719" class="share-reddit sd-button share-icon" href="https://codemanship.wordpress.com/2026/08/12/ai-software-development-what-does-the-data-say/?share=reddit" target="_blank" aria-labelledby="sharing-reddit-4719"&gt;
				&lt;span id="sharing-reddit-4719" hidden=""&gt;Share on Reddit (Opens in new window)&lt;/span&gt;
				&lt;span&gt;Reddit&lt;/span&gt;
			&lt;/a&gt;&lt;/li&gt;&lt;li class="share-email"&gt;&lt;a rel="nofollow noopener noreferrer" data-shared="sharing-email-4719" class="share-email sd-button share-icon" href="mailto:?subject=%5BShared%20Post%5D%20AI%20Software%20Development%20-%20What%20Does%20The%20Data%20Say%3F&amp;amp;body=https%3A%2F%2Fcodemanship.wordpress.com%2F2026%2F08%2F12%2Fai-software-development-what-does-the-data-say%2F&amp;amp;share=email" target="_blank" aria-labelledby="sharing-email-4719" data-email-share-error-title="Do you have email set up?" data-email-share-error-text="If you're having problems sharing via email, you might not have email set up for your browser. You may need to create a new email yourself." data-email-share-nonce="f7adcc12fb" data-email-share-track-url="https://codemanship.wordpress.com/2026/08/12/ai-software-development-what-does-the-data-say/?share=email"&gt;
				&lt;span id="sharing-email-4719" hidden=""&gt;Email a link to a friend (Opens in new window)&lt;/span&gt;
				&lt;span&gt;Email&lt;/span&gt;
			&lt;/a&gt;&lt;/li&gt;&lt;li class="share-end"&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="sharedaddy sd-block sd-like jetpack-likes-widget-wrapper jetpack-likes-widget-unloaded" id="like-post-wrapper-15031761-4719-6a7cc741583e4" data-src="//widgets.wp.com/likes/index.html?ver=20260812#blog_id=15031761&amp;amp;post_id=4719&amp;amp;origin=codemanship.wordpress.com&amp;amp;obj_id=15031761-4719-6a7cc741583e4" data-name="like-post-frame-15031761-4719-6a7cc741583e4" data-title="Like or Reblog"&gt;&lt;div class="likes-widget-placeholder post-likes-widget-placeholder" style="height: 55px;"&gt;&lt;span class="button"&gt;&lt;span&gt;Like&lt;/span&gt;&lt;/span&gt; &lt;span class="loading"&gt;Loading...&lt;/span&gt;&lt;/div&gt;&lt;span class="sd-text-color"&gt;&lt;/span&gt;&lt;a class="sd-link-color"&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div id="jp-relatedposts" class="jp-relatedposts" style="display: block;"&gt;
	&lt;h3 class="jp-relatedposts-headline"&gt;&lt;em&gt;Related&lt;/em&gt;&lt;/h3&gt;
&lt;div class="jp-relatedposts-items jp-relatedposts-items-minimal jp-relatedposts-grid "&gt;&lt;p class="jp-relatedposts-post jp-relatedposts-post0" data-post-id="4537" data-post-format="false"&gt;&lt;span class="jp-relatedposts-post-title"&gt;&lt;a class="jp-relatedposts-post-a" href="https://codemanship.wordpress.com/2026/05/28/what-if-the-real-key-to-ai-coding-is-old-fashioned-boring/" title="What If The Real Key To AI Coding Is Old-Fashioned &amp;amp;amp;&amp;amp;nbsp;Boring?" data-origin="4719" data-position="0"&gt;What If The Real Key To AI Coding Is Old-Fashioned &amp;amp;&amp;nbsp;Boring?&lt;/a&gt;&lt;/span&gt;&lt;time class="jp-relatedposts-post-date" datetime="May 28, 2026" style="display: block;"&gt;May 28, 2026&lt;/time&gt;&lt;span class="jp-relatedposts-post-context"&gt;In "a.i."&lt;/span&gt;&lt;/p&gt;&lt;p class="jp-relatedposts-post jp-relatedposts-post1" data-post-id="3470" data-post-format="false"&gt;&lt;span class="jp-relatedposts-post-title"&gt;&lt;a class="jp-relatedposts-post-a" href="https://codemanship.wordpress.com/2026/01/21/finally-proof-that-agentic-ai-scales-for-creating-broken-software/" title="Finally! Proof That Agentic AI Scales (For Creating Broken&amp;amp;nbsp;Software)" data-origin="4719" data-position="1"&gt;Finally! Proof That Agentic AI Scales (For Creating Broken&amp;nbsp;Software)&lt;/a&gt;&lt;/span&gt;&lt;time class="jp-relatedposts-post-date" datetime="January 21, 2026" style="display: block;"&gt;January 21, 2026&lt;/time&gt;&lt;span class="jp-relatedposts-post-context"&gt;In "a.i."&lt;/span&gt;&lt;/p&gt;&lt;p class="jp-relatedposts-post jp-relatedposts-post2" data-post-id="3943" data-post-format="false"&gt;&lt;span class="jp-relatedposts-post-title"&gt;&lt;a class="jp-relatedposts-post-a" href="https://codemanship.wordpress.com/2026/03/11/the-ai-ready-software-developer-21-stuck-in-a-doom-loop-drop-a-gear/" title="The AI-Ready Software Developer #21 &amp;amp;#8211; Stuck In A &amp;amp;#8220;Doom Loop&amp;amp;#8221;? Drop A&amp;amp;nbsp;Gear" data-origin="4719" data-position="2"&gt;The AI-Ready Software Developer #21 – Stuck In A “Doom Loop”? Drop A&amp;nbsp;Gear&lt;/a&gt;&lt;/span&gt;&lt;time class="jp-relatedposts-post-date" datetime="March 11, 2026" style="display: block;"&gt;March 11, 2026&lt;/time&gt;&lt;span class="jp-relatedposts-post-context"&gt;In "a.i."&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="author-info"&gt;
	&lt;div class="author-avatar"&gt;
		&lt;img referrerpolicy="no-referrer" alt="Unknown's avatar" src="https://1.gravatar.com/avatar/aadcfbd208e65a0829f5d259192a5886454439a708e425500c59c535e28ae081?s=42&amp;amp;d=identicon&amp;amp;r=G" srcset="https://1.gravatar.com/avatar/aadcfbd208e65a0829f5d259192a5886454439a708e425500c59c535e28ae081?s=42&amp;amp;d=identicon&amp;amp;r=G 1x, https://1.gravatar.com/avatar/aadcfbd208e65a0829f5d259192a5886454439a708e425500c59c535e28ae081?s=63&amp;amp;d=identicon&amp;amp;r=G 1.5x, https://1.gravatar.com/avatar/aadcfbd208e65a0829f5d259192a5886454439a708e425500c59c535e28ae081?s=84&amp;amp;d=identicon&amp;amp;r=G 2x, https://1.gravatar.com/avatar/aadcfbd208e65a0829f5d259192a5886454439a708e425500c59c535e28ae081?s=126&amp;amp;d=identicon&amp;amp;r=G 3x, https://1.gravatar.com/avatar/aadcfbd208e65a0829f5d259192a5886454439a708e425500c59c535e28ae081?s=168&amp;amp;d=identicon&amp;amp;r=G 4x" class="avatar avatar-42 wp-hovercard-attachment grav-hashed grav-hijack" height="42" width="42" decoding="async"&gt;	&lt;/div&gt;&lt;!-- .author-avatar --&gt;

	&lt;div class="author-description"&gt;
		&lt;h2 class="author-title"&gt;&lt;span class="author-heading"&gt;Author:&lt;/span&gt; codemanship&lt;/h2&gt;

		&lt;p class="author-bio"&gt;
			Founder of Codemanship Ltd and code craft coach and trainer			&lt;a class="author-link" href="https://codemanship.wordpress.com/author/codemanship/" rel="author"&gt;
				View all posts by codemanship			&lt;/a&gt;
		&lt;/p&gt;&lt;!-- .author-bio --&gt;
	&lt;/div&gt;&lt;!-- .author-description --&gt;
&lt;/div&gt;&lt;!-- .author-info --&gt;
	&lt;/div&gt;&lt;!-- .entry-content --&gt;

	&lt;footer class="entry-footer"&gt;
		&lt;span class="byline"&gt;&lt;span class="author vcard"&gt;&lt;img referrerpolicy="no-referrer" alt="Unknown's avatar" src="https://1.gravatar.com/avatar/aadcfbd208e65a0829f5d259192a5886454439a708e425500c59c535e28ae081?s=49&amp;amp;d=identicon&amp;amp;r=G" srcset="https://1.gravatar.com/avatar/aadcfbd208e65a0829f5d259192a5886454439a708e425500c59c535e28ae081?s=49&amp;amp;d=identicon&amp;amp;r=G 1x, https://1.gravatar.com/avatar/aadcfbd208e65a0829f5d259192a5886454439a708e425500c59c535e28ae081?s=74&amp;amp;d=identicon&amp;amp;r=G 1.5x, https://1.gravatar.com/avatar/aadcfbd208e65a0829f5d259192a5886454439a708e425500c59c535e28ae081?s=98&amp;amp;d=identicon&amp;amp;r=G 2x, https://1.gravatar.com/avatar/aadcfbd208e65a0829f5d259192a5886454439a708e425500c59c535e28ae081?s=147&amp;amp;d=identicon&amp;amp;r=G 3x, https://1.gravatar.com/avatar/aadcfbd208e65a0829f5d259192a5886454439a708e425500c59c535e28ae081?s=196&amp;amp;d=identicon&amp;amp;r=G 4x" class="avatar avatar-49 wp-hovercard-attachment grav-hashed grav-hijack" height="49" width="49" decoding="async"&gt;&lt;span class="screen-reader-text"&gt;Author &lt;/span&gt; &lt;a class="url fn n" href="https://codemanship.wordpress.com/author/codemanship/"&gt;codemanship&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="posted-on"&gt;&lt;span class="screen-reader-text"&gt;Posted on &lt;/span&gt;&lt;a href="https://codemanship.wordpress.com/2026/08/12/ai-software-development-what-does-the-data-say/" rel="bookmark"&gt;&lt;time class="entry-date published" datetime="2026-08-12T18:41:50+01:00"&gt;August 12, 2026&lt;/time&gt;&lt;time class="updated" datetime="2026-08-12T18:46:26+01:00"&gt;August 12, 2026&lt;/time&gt;&lt;/a&gt;&lt;/span&gt;&lt;span class="cat-links"&gt;&lt;span class="screen-reader-text"&gt;Categories &lt;/span&gt;&lt;a href="https://codemanship.wordpress.com/category/a-i/" rel="category tag"&gt;a.i.&lt;/a&gt;&lt;/span&gt;			&lt;/footer&gt;&lt;!-- .entry-footer --&gt;
&lt;/article&gt;&lt;!-- #post-4719 --&gt;

&lt;div id="comments" class="comments-area"&gt;

	
	
		&lt;div id="respond" class="comment-respond"&gt;
		&lt;h2 id="reply-title" class="comment-reply-title"&gt;Leave a comment &lt;small&gt;&lt;a rel="nofollow" id="cancel-comment-reply-link" href="/2026/08/12/ai-software-development-what-does-the-data-say/#respond" style="display:none;"&gt;Cancel reply&lt;/a&gt;&lt;/small&gt;&lt;/h2&gt;&lt;form action="https://codemanship.wordpress.com/wp-comments-post.php" method="post" id="commentform" class="comment-form"&gt;


&lt;div class="comment-form__verbum transparent"&gt;&lt;/div&gt;&lt;div class="verbum-form-meta"&gt;&lt;input type="hidden" name="comment_post_ID" value="4719" id="comment_post_ID"&gt;
&lt;input type="hidden" name="comment_parent" id="comment_parent" value="0"&gt;

			&lt;input type="hidden" name="highlander_comment_nonce" id="highlander_comment_nonce" value="78997a4899"&gt;
			&lt;input type="hidden" name="verbum_show_subscription_modal" value=""&gt;&lt;/div&gt;&lt;p style="display: none;"&gt;&lt;input type="hidden" id="akismet_comment_nonce" name="akismet_comment_nonce" value="26b062dc38"&gt;&lt;/p&gt;&lt;p style="display: none !important;" class="akismet-fields-container" data-prefix="ak_"&gt;&lt;label&gt;Δ&lt;textarea name="ak_hp_textarea" cols="45" rows="8" maxlength="100"&gt;&lt;/textarea&gt;&lt;/label&gt;&lt;input type="hidden" id="ak_js_1" name="ak_js" value="1786563258901"&gt;&lt;script&gt;
document.getElementById( "ak_js_1" ).setAttribute( "value", ( new Date() ).getTime() );
&lt;/script&gt;
&lt;/p&gt;&lt;/form&gt;	&lt;/div&gt;&lt;!-- #respond --&gt;
	
&lt;/div&gt;&lt;!-- .comments-area --&gt;

	&lt;nav class="navigation post-navigation" aria-label="Posts"&gt;
		&lt;h2 class="screen-reader-text"&gt;Post navigation&lt;/h2&gt;
		&lt;div class="nav-links"&gt;&lt;div class="nav-previous"&gt;&lt;a href="https://codemanship.wordpress.com/2026/08/01/do-your-quality-gates-see-the-brown-mms-in-the-bowl/" rel="prev"&gt;&lt;span class="meta-nav" aria-hidden="true"&gt;Previous&lt;/span&gt; &lt;span class="screen-reader-text"&gt;Previous post:&lt;/span&gt; &lt;span class="post-title"&gt;Do Your Quality Gates See The Brown M&amp;amp;Ms In The&amp;nbsp;Bowl?&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;
	&lt;/nav&gt;
	&lt;/main&gt;&lt;!-- .site-main --&gt;

	
&lt;/div&gt;&lt;!-- .content-area --&gt;


	&lt;aside id="secondary" class="sidebar widget-area"&gt;
		&lt;section id="search-2" class="widget widget_search"&gt;
&lt;form role="search" method="get" class="search-form" action="https://codemanship.wordpress.com/"&gt;
	&lt;label&gt;
		&lt;span class="screen-reader-text"&gt;
			Search for:		&lt;/span&gt;
		&lt;input type="search" class="search-field" placeholder="Search …" value="" name="s"&gt;
	&lt;/label&gt;
	&lt;button type="submit" class="search-submit"&gt;&lt;span class="screen-reader-text"&gt;
		Search	&lt;/span&gt;&lt;/button&gt;
&lt;/form&gt;
&lt;/section&gt;&lt;section id="block-5" class="widget widget_block widget_text"&gt;
&lt;p class="wp-block-paragraph"&gt;&lt;a href="https://codemanship.co.uk/"&gt;Visit my site&lt;/a&gt; for details of Training &amp;amp; Coaching in Technical Practices for rapid, reliable and sustainable software delivery, with and without AI&lt;/p&gt;
&lt;/section&gt;&lt;section id="block-3" class="widget widget_block"&gt;&lt;div class="wp-block-jetpack-subscriptions__supports-newline wp-block-jetpack-subscriptions"&gt;
		&lt;div&gt;
			&lt;div&gt;
				&lt;div&gt;
					&lt;p&gt;
						&lt;a href="https://codemanship.wordpress.com/?post_type=post&amp;amp;p=4719" style="font-size: 16px;padding: 15px 23px 15px 23px;margin: 0; margin-left: 10px;border-radius: 0px;border-width: 1px; background-color: #113AF5; color: #FFFFFF; text-decoration: none; white-space: nowrap; margin-left: 0"&gt;Subscribe&lt;/a&gt;
					&lt;/p&gt;
				&lt;/div&gt;
			&lt;/div&gt;
		&lt;/div&gt;
	&lt;/div&gt;&lt;/section&gt;
		&lt;section id="recent-posts-2" class="widget widget_recent_entries"&gt;
		&lt;h2 class="widget-title"&gt;Recent Posts&lt;/h2&gt;&lt;nav aria-label="Recent Posts"&gt;
		&lt;ul&gt;
											&lt;li&gt;
					&lt;a href="https://codemanship.wordpress.com/2026/08/12/ai-software-development-what-does-the-data-say/" aria-current="page"&gt;AI Software Development – What Does The Data&amp;nbsp;Say?&lt;/a&gt;
									&lt;/li&gt;
											&lt;li&gt;
					&lt;a href="https://codemanship.wordpress.com/2026/08/01/do-your-quality-gates-see-the-brown-mms-in-the-bowl/"&gt;Do Your Quality Gates See The Brown M&amp;amp;Ms In The&amp;nbsp;Bowl?&lt;/a&gt;
									&lt;/li&gt;
											&lt;li&gt;
					&lt;a href="https://codemanship.wordpress.com/2026/07/19/the-power-of-why/"&gt;The Power Of “Why?”&lt;/a&gt;
									&lt;/li&gt;
											&lt;li&gt;
					&lt;a href="https://codemanship.wordpress.com/2026/07/15/feedback-latency-learning-productivity/"&gt;Feedback Latency, Learning &amp;amp; “Productivity”&lt;/a&gt;
									&lt;/li&gt;
											&lt;li&gt;
					&lt;a href="https://codemanship.wordpress.com/2026/06/24/even-if-we-could-extend-the-horizons-of-autonomous-coding-agents-does-that-mean-we-should/"&gt;Even If We Could Extend The Horizons of Autonomous Coding Agents, Does That Mean We&amp;nbsp;Should?&lt;/a&gt;
									&lt;/li&gt;
					&lt;/ul&gt;

		&lt;/nav&gt;&lt;/section&gt;&lt;section id="archives-2" class="widget widget_archive"&gt;&lt;h2 class="widget-title"&gt;Archives&lt;/h2&gt;&lt;nav aria-label="Archives"&gt;
			&lt;ul&gt;
					&lt;li&gt;&lt;a href="https://codemanship.wordpress.com/2026/08/"&gt;August 2026&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="https://codemanship.wordpress.com/2026/07/"&gt;July 2026&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="https://codemanship.wordpress.com/2026/06/"&gt;June 2026&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="https://codemanship.wordpress.com/2026/05/"&gt;May 2026&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="https://codemanship.wordpress.com/2026/04/"&gt;April 2026&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="https://codemanship.wordpress.com/2026/03/"&gt;March 2026&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="https://codemanship.wordpress.com/2026/02/"&gt;February 2026&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="https://codemanship.wordpress.com/2026/01/"&gt;January 2026&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="https://codemanship.wordpress.com/2025/12/"&gt;December 2025&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="https://codemanship.wordpress.com/2025/11/"&gt;November 2025&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="https://codemanship.wordpress.com/2025/10/"&gt;October 2025&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="https://codemanship.wordpress.com/2025/09/"&gt;September 2025&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="https://codemanship.wordpress.com/2025/08/"&gt;August 2025&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="https://codemanship.wordpress.com/2025/07/"&gt;July 2025&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="https://codemanship.wordpress.com/2025/06/"&gt;June 2025&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="https://codemanship.wordpress.com/2025/05/"&gt;May 2025&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="https://codemanship.wordpress.com/2025/04/"&gt;April 2025&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="https://codemanship.wordpress.com/2025/03/"&gt;March 2025&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="https://codemanship.wordpress.com/2025/02/"&gt;February 2025&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="https://codemanship.wordpress.com/2025/01/"&gt;January 2025&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="https://codemanship.wordpress.com/2024/12/"&gt;December 2024&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="https://codemanship.wordpress.com/2023/12/"&gt;December 2023&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="https://codemanship.wordpress.com/2023/11/"&gt;November 2023&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="https://codemanship.wordpress.com/2023/09/"&gt;September 2023&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="https://codemanship.wordpress.com/2021/09/"&gt;September 2021&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="https://codemanship.wordpress.com/2021/08/"&gt;August 2021&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="https://codemanship.wordpress.com/2021/07/"&gt;July 2021&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="https://codemanship.wordpress.com/2021/05/"&gt;May 2021&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="https://codemanship.wordpress.com/2021/04/"&gt;April 2021&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="https://codemanship.wordpress.com/2021/03/"&gt;March 2021&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="https://codemanship.wordpress.com/2021/02/"&gt;February 2021&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="https://codemanship.wordpress.com/2021/01/"&gt;January 2021&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="https://codemanship.wordpress.com/2020/12/"&gt;December 2020&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="https://codemanship.wordpress.com/2020/10/"&gt;October 2020&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="https://codemanship.wordpress.com/2020/09/"&gt;September 2020&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="https://codemanship.wordpress.com/2020/08/"&gt;August 2020&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="https://codemanship.wordpress.com/2020/07/"&gt;July 2020&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="https://codemanship.wordpress.com/2020/06/"&gt;June 2020&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="https://codemanship.wordpress.com/2020/05/"&gt;May 2020&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="https://codemanship.wordpress.com/2020/04/"&gt;April 2020&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="https://codemanship.wordpress.com/2020/03/"&gt;March 2020&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="https://codemanship.wordpress.com/2020/02/"&gt;February 2020&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="https://codemanship.wordpress.com/2020/01/"&gt;January 2020&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="https://codemanship.wordpress.com/2019/12/"&gt;December 2019&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="https://codemanship.wordpress.com/2019/11/"&gt;November 2019&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="https://codemanship.wordpress.com/2019/10/"&gt;October 2019&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="https://codemanship.wordpress.com/2019/09/"&gt;September 2019&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="https://codemanship.wordpress.com/2019/08/"&gt;August 2019&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="https://codemanship.wordpress.com/2019/07/"&gt;July 2019&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="https://codemanship.wordpress.com/2019/06/"&gt;June 2019&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="https://codemanship.wordpress.com/2019/05/"&gt;May 2019&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="https://codemanship.wordpress.com/2019/04/"&gt;April 2019&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="https://codemanship.wordpress.com/2019/03/"&gt;March 2019&lt;/a&gt;&lt;/li&gt;
			&lt;/ul&gt;

			&lt;/nav&gt;&lt;/section&gt;&lt;section id="categories-2" class="widget widget_categories"&gt;&lt;h2 class="widget-title"&gt;Categories&lt;/h2&gt;&lt;nav aria-label="Categories"&gt;
			&lt;ul&gt;
					&lt;li class="cat-item cat-item-670085548"&gt;&lt;a href="https://codemanship.wordpress.com/category/nobacklogs/"&gt;#NoBacklogs&lt;/a&gt;
&lt;/li&gt;
	&lt;li class="cat-item cat-item-2735261"&gt;&lt;a href="https://codemanship.wordpress.com/category/a-i/"&gt;a.i.&lt;/a&gt;
&lt;/li&gt;
	&lt;li class="cat-item cat-item-3562"&gt;&lt;a href="https://codemanship.wordpress.com/category/agility/"&gt;agility&lt;/a&gt;
&lt;/li&gt;
	&lt;li class="cat-item cat-item-594837"&gt;&lt;a href="https://codemanship.wordpress.com/category/apprenticeships/"&gt;apprenticeships&lt;/a&gt;
&lt;/li&gt;
	&lt;li class="cat-item cat-item-2290"&gt;&lt;a href="https://codemanship.wordpress.com/category/architecture/"&gt;architecture&lt;/a&gt;
&lt;/li&gt;
	&lt;li class="cat-item cat-item-330761"&gt;&lt;a href="https://codemanship.wordpress.com/category/capability/"&gt;capability&lt;/a&gt;
&lt;/li&gt;
	&lt;li class="cat-item cat-item-34898103"&gt;&lt;a href="https://codemanship.wordpress.com/category/code-quality/code-comprehension/"&gt;code comprehension&lt;/a&gt;
&lt;/li&gt;
	&lt;li class="cat-item cat-item-52290118"&gt;&lt;a href="https://codemanship.wordpress.com/category/code-craft/"&gt;code craft&lt;/a&gt;
&lt;/li&gt;
	&lt;li class="cat-item cat-item-637195"&gt;&lt;a href="https://codemanship.wordpress.com/category/code-quality/"&gt;code quality&lt;/a&gt;
&lt;/li&gt;
	&lt;li class="cat-item cat-item-214618"&gt;&lt;a href="https://codemanship.wordpress.com/category/concurrency/"&gt;concurrency&lt;/a&gt;
&lt;/li&gt;
	&lt;li class="cat-item cat-item-331916954"&gt;&lt;a href="https://codemanship.wordpress.com/category/context-engineering/"&gt;context engineering&lt;/a&gt;
&lt;/li&gt;
	&lt;li class="cat-item cat-item-32361710"&gt;&lt;a href="https://codemanship.wordpress.com/category/continuous-delivery/"&gt;continuous delivery&lt;/a&gt;
&lt;/li&gt;
	&lt;li class="cat-item cat-item-45037571"&gt;&lt;a href="https://codemanship.wordpress.com/category/continuous-inspection/"&gt;continuous inspection&lt;/a&gt;
&lt;/li&gt;
	&lt;li class="cat-item cat-item-878714"&gt;&lt;a href="https://codemanship.wordpress.com/category/context-engineering/cress/"&gt;cress&lt;/a&gt;
&lt;/li&gt;
	&lt;li class="cat-item cat-item-11379259"&gt;&lt;a href="https://codemanship.wordpress.com/category/designprinciples/"&gt;designprinciples&lt;/a&gt;
&lt;/li&gt;
	&lt;li class="cat-item cat-item-787605825"&gt;&lt;a href="https://codemanship.wordpress.com/category/feedback-loops/feedback-latency/"&gt;feedback latency&lt;/a&gt;
&lt;/li&gt;
	&lt;li class="cat-item cat-item-2190936"&gt;&lt;a href="https://codemanship.wordpress.com/category/feedback-loops/"&gt;feedback loops&lt;/a&gt;
&lt;/li&gt;
	&lt;li class="cat-item cat-item-116486"&gt;&lt;a href="https://codemanship.wordpress.com/category/functional-programming/"&gt;functional programming&lt;/a&gt;
&lt;/li&gt;
	&lt;li class="cat-item cat-item-11870"&gt;&lt;a href="https://codemanship.wordpress.com/category/goals/"&gt;goals&lt;/a&gt;
&lt;/li&gt;
	&lt;li class="cat-item cat-item-8855747"&gt;&lt;a href="https://codemanship.wordpress.com/category/high-integrity/"&gt;high-integrity&lt;/a&gt;
&lt;/li&gt;
	&lt;li class="cat-item cat-item-7885"&gt;&lt;a href="https://codemanship.wordpress.com/category/leadership/"&gt;leadership&lt;/a&gt;
&lt;/li&gt;
	&lt;li class="cat-item cat-item-264"&gt;&lt;a href="https://codemanship.wordpress.com/category/learning/"&gt;learning&lt;/a&gt;
&lt;/li&gt;
	&lt;li class="cat-item cat-item-33253"&gt;&lt;a href="https://codemanship.wordpress.com/category/mentoring/"&gt;mentoring&lt;/a&gt;
&lt;/li&gt;
	&lt;li class="cat-item cat-item-660"&gt;&lt;a href="https://codemanship.wordpress.com/category/people/"&gt;people&lt;/a&gt;
&lt;/li&gt;
	&lt;li class="cat-item cat-item-2704"&gt;&lt;a href="https://codemanship.wordpress.com/category/productivity/"&gt;productivity&lt;/a&gt;
&lt;/li&gt;
	&lt;li class="cat-item cat-item-54712"&gt;&lt;a href="https://codemanship.wordpress.com/category/refactoring/"&gt;refactoring&lt;/a&gt;
&lt;/li&gt;
	&lt;li class="cat-item cat-item-16577"&gt;&lt;a href="https://codemanship.wordpress.com/category/requirements/"&gt;requirements&lt;/a&gt;
&lt;/li&gt;
	&lt;li class="cat-item cat-item-17266"&gt;&lt;a href="https://codemanship.wordpress.com/category/simplicity/"&gt;simplicity&lt;/a&gt;
&lt;/li&gt;
	&lt;li class="cat-item cat-item-2301"&gt;&lt;a href="https://codemanship.wordpress.com/category/software-development/"&gt;software development&lt;/a&gt;
&lt;/li&gt;
	&lt;li class="cat-item cat-item-76604"&gt;&lt;a href="https://codemanship.wordpress.com/category/tdd/"&gt;tdd&lt;/a&gt;
&lt;/li&gt;
	&lt;li class="cat-item cat-item-6228"&gt;&lt;a href="https://codemanship.wordpress.com/category/teams/"&gt;teams&lt;/a&gt;
&lt;/li&gt;
	&lt;li class="cat-item cat-item-12"&gt;&lt;a href="https://codemanship.wordpress.com/category/testing/"&gt;testing&lt;/a&gt;
&lt;/li&gt;
	&lt;li class="cat-item cat-item-943"&gt;&lt;a href="https://codemanship.wordpress.com/category/training/"&gt;training&lt;/a&gt;
&lt;/li&gt;
	&lt;li class="cat-item cat-item-518"&gt;&lt;a href="https://codemanship.wordpress.com/category/trends/"&gt;trends&lt;/a&gt;
&lt;/li&gt;
	&lt;li class="cat-item cat-item-57610"&gt;&lt;a href="https://codemanship.wordpress.com/category/trust/"&gt;trust&lt;/a&gt;
&lt;/li&gt;
	&lt;li class="cat-item cat-item-1"&gt;&lt;a href="https://codemanship.wordpress.com/category/uncategorized/"&gt;Uncategorized&lt;/a&gt;
&lt;/li&gt;
			&lt;/ul&gt;

			&lt;/nav&gt;&lt;/section&gt;	&lt;/aside&gt;&lt;!-- .sidebar .widget-area --&gt;

		&lt;/div&gt;&lt;!-- .site-content --&gt;

		&lt;footer id="colophon" class="site-footer"&gt;
							&lt;nav class="main-navigation" aria-label="Footer Primary Menu"&gt;
					&lt;div class="menu-codemanship-container"&gt;&lt;ul id="menu-codemanship-1" class="primary-menu"&gt;&lt;li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-home menu-item-65"&gt;&lt;a href="https://codemanship.wordpress.com"&gt;Home&lt;/a&gt;&lt;/li&gt;
&lt;li class="menu-item menu-item-type-post_type menu-item-object-page menu-item-66"&gt;&lt;a href="https://codemanship.wordpress.com/about/"&gt;About&lt;/a&gt;&lt;/li&gt;
&lt;li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-67"&gt;&lt;a href="https://www.codemanship.co.uk"&gt;Training&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;				&lt;/nav&gt;&lt;!-- .main-navigation --&gt;
			
			
			&lt;div class="site-info"&gt;
								&lt;span class="site-title"&gt;&lt;a href="https://codemanship.wordpress.com/" rel="home"&gt;Codemanship's Blog&lt;/a&gt;&lt;/span&gt;
								&lt;a href="https://wordpress.com/?ref=footer_blog" rel="nofollow"&gt;Blog at WordPress.com.&lt;/a&gt;
			&lt;/div&gt;&lt;!-- .site-info --&gt;
		&lt;/footer&gt;&lt;!-- .site-footer --&gt;
	&lt;/div&gt;&lt;!-- .site-inner --&gt;
&lt;/div&gt;&lt;!-- .site --&gt;

&lt;!--  --&gt;
&lt;script type="speculationrules"&gt;
{"prefetch":[{"source":"document","where":{"and":[{"href_matches":"/*"},{"not":{"href_matches":["/wp-*.php","/wp-admin/*","/files/*","/wp-content/*","/wp-content/plugins/*","/wp-content/themes/pub/twentysixteen/*","/*\\?(.+)"]}},{"not":{"selector_matches":"a[rel~=\"nofollow\"]"}},{"not":{"selector_matches":".no-prefetch, .no-prefetch a"}}]},"eagerness":"conservative"}]}
&lt;/script&gt;
&lt;script id="grofiles-cards-js" src="//0.gravatar.com/js/hovercards/hovercards.min.js?ver=202633d1133547e8a1f2801609f51cef12522abe7f6647d869e9fbc974fe356a37e613"&gt;&lt;/script&gt;
&lt;script id="wpgroho-js-extra"&gt;
var WPGroHo = {"my_hash":""};
//# sourceURL=wpgroho-js-extra
&lt;/script&gt;
&lt;script crossorigin="anonymous" type="text/javascript" src="/wp-content/mu-plugins/gravatar-hovercards/wpgroho.js?m=1610363240i"&gt;&lt;/script&gt;

	&lt;script&gt;
		// Initialize and attach hovercards to all gravatars
		( function() {
			function init() {
				if ( typeof Gravatar === 'undefined' ) {
					return;
				}

				if ( typeof Gravatar.init !== 'function' ) {
					return;
				}

				Gravatar.profile_cb = function ( hash, id ) {
					WPGroHo.syncProfileData( hash, id );
				};

				Gravatar.my_hash = WPGroHo.my_hash;
				Gravatar.init(
					'body',
					'#wp-admin-bar-my-account',
					{
						i18n: {
							'Edit your profile →': 'Edit your profile →',
							'View profile →': 'View profile →',
							'Contact': 'Contact',
							'Send money': 'Send money',
							'Sorry, we are unable to load this Gravatar profile.': 'Sorry, we are unable to load this Gravatar profile.',
							'Gravatar not found.': 'Gravatar not found.',
							'Too Many Requests.': 'Too Many Requests.',
							'Internal Server Error.': 'Internal Server Error.',
							'Is this you?': 'Is this you?',
							'Claim your free profile.': 'Claim your free profile.',
							'Email': 'Email',
							'Home Phone': 'Home Phone',
							'Work Phone': 'Work Phone',
							'Cell Phone': 'Cell Phone',
							'Contact Form': 'Contact Form',
							'Calendar': 'Calendar',
						},
					}
				);
			}

			if ( document.readyState !== 'loading' ) {
				init();
			} else {
				document.addEventListener( 'DOMContentLoaded', init );
			}
		} )();
	&lt;/script&gt;

		&lt;div style="display:none"&gt;
	&lt;div class="grofile-hash-map-f0e9e91d8664a0e62c1d48d044b8825d"&gt;
	&lt;/div&gt;
	&lt;/div&gt;
		&lt;div id="actionbar" dir="ltr" class="actnbr-pub-twentysixteen actnbr-has-follow actnbr-has-actions"&gt;
		&lt;ul&gt;
								&lt;li class="actnbr-btn actnbr-hidden"&gt;
						&lt;a class="actnbr-action actnbr-actn-comment" href="https://codemanship.wordpress.com/2026/08/12/ai-software-development-what-does-the-data-say/#respond"&gt;
							&lt;svg class="gridicon gridicons-comment" height="20" width="20" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&gt;&lt;g&gt;&lt;path d="M12 16l-5 5v-5H5c-1.1 0-2-.9-2-2V5c0-1.1.9-2 2-2h14c1.1 0 2 .9 2 2v9c0 1.1-.9 2-2 2h-7z"&gt;&lt;/path&gt;&lt;/g&gt;&lt;/svg&gt;							&lt;span&gt;Comment						&lt;/span&gt;
						&lt;/a&gt;
					&lt;/li&gt;
									&lt;li class="actnbr-btn actnbr-hidden"&gt;
						&lt;a class="actnbr-action actnbr-actn-reblog" href=""&gt;
							&lt;svg class="gridicon gridicons-reblog" height="20" width="20" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&gt;&lt;g&gt;&lt;path d="M22.086 9.914L20 7.828V18c0 1.105-.895 2-2 2h-7v-2h7V7.828l-2.086 2.086L14.5 8.5 19 4l4.5 4.5-1.414 1.414zM6 16.172V6h7V4H6c-1.105 0-2 .895-2 2v10.172l-2.086-2.086L.5 15.5 5 20l4.5-4.5-1.414-1.414L6 16.172z"&gt;&lt;/path&gt;&lt;/g&gt;&lt;/svg&gt;&lt;span&gt;Reblog&lt;/span&gt;
						&lt;/a&gt;
					&lt;/li&gt;
									&lt;li class="actnbr-btn actnbr-hidden"&gt;
								&lt;a class="actnbr-action actnbr-actn-follow " href=""&gt;
			&lt;svg class="gridicon" height="20" width="20" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"&gt;&lt;path clip-rule="evenodd" d="m4 4.5h12v6.5h1.5v-6.5-1.5h-1.5-12-1.5v1.5 10.5c0 1.1046.89543 2 2 2h7v-1.5h-7c-.27614 0-.5-.2239-.5-.5zm10.5 2h-9v1.5h9zm-5 3h-4v1.5h4zm3.5 1.5h-1v1h1zm-1-1.5h-1.5v1.5 1 1.5h1.5 1 1.5v-1.5-1-1.5h-1.5zm-2.5 2.5h-4v1.5h4zm6.5 1.25h1.5v2.25h2.25v1.5h-2.25v2.25h-1.5v-2.25h-2.25v-1.5h2.25z" fill-rule="evenodd"&gt;&lt;/path&gt;&lt;/svg&gt;
			&lt;span&gt;Subscribe&lt;/span&gt;
		&lt;/a&gt;
		&lt;a class="actnbr-action actnbr-actn-following  no-display" href=""&gt;
			&lt;svg class="gridicon" height="20" width="20" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="none"&gt;&lt;path fill-rule="evenodd" clip-rule="evenodd" d="M16 4.5H4V15C4 15.2761 4.22386 15.5 4.5 15.5H11.5V17H4.5C3.39543 17 2.5 16.1046 2.5 15V3H17.5V12.5H16V4.5ZM5.5 6.5H14.5V8H5.5V6.5ZM5.5 9.5H9.5V11H5.5V9.5ZM12 11H13V12H12V11ZM10.5 9.5H14.5V13.5H10.5V9.5ZM5.5 12H9.5V13.5H5.5V12Z" fill="#008A20"&gt;&lt;/path&gt;&lt;path d="M19.5303 15.0303L15.5 19.0605L12.9697 16.5303L14.0303 15.4697L15.5 16.9395L18.4697 13.9697L19.5303 15.0303Z" fill="#008A20"&gt;&lt;/path&gt;&lt;/svg&gt;
			&lt;span&gt;Subscribed&lt;/span&gt;
		&lt;/a&gt;
							&lt;div class="actnbr-popover tip tip-top-left actnbr-notice" id="follow-bubble"&gt;
							&lt;div class="tip-arrow"&gt;&lt;/div&gt;
							&lt;div class="tip-inner actnbr-follow-bubble"&gt;
															&lt;ul&gt;
											&lt;li class="actnbr-sitename"&gt;
			&lt;a href="https://codemanship.wordpress.com"&gt;
				&lt;img loading="lazy" alt="" src="https://codemanship.wordpress.com/wp-content/uploads/2017/08/cropped-codemanship3_twitter_avatar.jpg?w=50" srcset="https://codemanship.wordpress.com/wp-content/uploads/2017/08/cropped-codemanship3_twitter_avatar.jpg?w=50 1x, https://codemanship.wordpress.com/wp-content/uploads/2017/08/cropped-codemanship3_twitter_avatar.jpg?w=75 1.5x, https://codemanship.wordpress.com/wp-content/uploads/2017/08/cropped-codemanship3_twitter_avatar.jpg?w=100 2x, https://codemanship.wordpress.com/wp-content/uploads/2017/08/cropped-codemanship3_twitter_avatar.jpg?w=150 3x, https://codemanship.wordpress.com/wp-content/uploads/2017/08/cropped-codemanship3_twitter_avatar.jpg?w=200 4x" class="avatar avatar-50" height="50" width="50"&gt;				Codemanship's Blog			&lt;/a&gt;
		&lt;/li&gt;
										&lt;div class="actnbr-message no-display"&gt;&lt;/div&gt;
									&lt;form method="post" action="https://subscribe.wordpress.com" accept-charset="utf-8" style="display: none;"&gt;
																						&lt;div class="actnbr-follow-count"&gt;Join 126 other subscribers&lt;/div&gt;
																					&lt;div&gt;
										&lt;input type="email" name="email" placeholder="Enter your email address" class="actnbr-email-field" aria-label="Enter your email address"&gt;
										&lt;/div&gt;
										&lt;input type="hidden" name="action" value="subscribe"&gt;
										&lt;input type="hidden" name="blog_id" value="15031761"&gt;
										&lt;input type="hidden" name="source" value="https://codemanship.wordpress.com/2026/08/12/ai-software-development-what-does-the-data-say/"&gt;
										&lt;input type="hidden" name="sub-type" value="actionbar-follow"&gt;
										&lt;input type="hidden" id="_wpnonce" name="_wpnonce" value="b4e41ffb1a"&gt;										&lt;div class="actnbr-button-wrap"&gt;
											&lt;button type="submit" value="Sign me up"&gt;
												Sign me up											&lt;/button&gt;
										&lt;/div&gt;
									&lt;/form&gt;
									&lt;li class="actnbr-login-nudge"&gt;
										&lt;div&gt;
											Already have a WordPress.com account? &lt;a href="https://wordpress.com/log-in?redirect_to=https%3A%2F%2Fcodemanship.wordpress.com%2F2026%2F08%2F12%2Fai-software-development-what-does-the-data-say%2F&amp;amp;signup_flow=account"&gt;Log in now.&lt;/a&gt;										&lt;/div&gt;
									&lt;/li&gt;
								&lt;/ul&gt;
															&lt;/div&gt;
						&lt;/div&gt;
					&lt;/li&gt;
									&lt;li class="actnbr-btn actnbr-hidden no-display" onclick="javascript:__tcfapi( 'showUi' );"&gt;
						&lt;a class="actnbr-action actnbr-actn-privacy" href="#"&gt;
							&lt;svg class="gridicon gridicons-info-outline" height="20" width="20" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&gt;&lt;g&gt;&lt;path d="M13 9h-2V7h2v2zm0 2h-2v6h2v-6zm-1-7c-4.41 0-8 3.59-8 8s3.59 8 8 8 8-3.59 8-8-3.59-8-8-8m0-2c5.523 0 10 4.477 10 10s-4.477 10-10 10S2 17.523 2 12 6.477 2 12 2z"&gt;&lt;/path&gt;&lt;/g&gt;&lt;/svg&gt;							&lt;span&gt;Privacy						&lt;/span&gt;
						&lt;/a&gt;
					&lt;/li&gt;
							&lt;li class="actnbr-ellipsis actnbr-hidden"&gt;
				&lt;svg class="gridicon gridicons-ellipsis" height="24" width="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&gt;&lt;g&gt;&lt;path d="M7 12c0 1.104-.896 2-2 2s-2-.896-2-2 .896-2 2-2 2 .896 2 2zm12-2c-1.104 0-2 .896-2 2s.896 2 2 2 2-.896 2-2-.896-2-2-2zm-7 0c-1.104 0-2 .896-2 2s.896 2 2 2 2-.896 2-2-.896-2-2-2z"&gt;&lt;/path&gt;&lt;/g&gt;&lt;/svg&gt;				&lt;div class="actnbr-popover tip tip-top-left actnbr-more"&gt;
					&lt;div class="tip-arrow"&gt;&lt;/div&gt;
					&lt;div class="tip-inner"&gt;
						&lt;ul&gt;
								&lt;li class="actnbr-sitename"&gt;
			&lt;a href="https://codemanship.wordpress.com"&gt;
				&lt;img loading="lazy" alt="" src="https://codemanship.wordpress.com/wp-content/uploads/2017/08/cropped-codemanship3_twitter_avatar.jpg?w=50" srcset="https://codemanship.wordpress.com/wp-content/uploads/2017/08/cropped-codemanship3_twitter_avatar.jpg?w=50 1x, https://codemanship.wordpress.com/wp-content/uploads/2017/08/cropped-codemanship3_twitter_avatar.jpg?w=75 1.5x, https://codemanship.wordpress.com/wp-content/uploads/2017/08/cropped-codemanship3_twitter_avatar.jpg?w=100 2x, https://codemanship.wordpress.com/wp-content/uploads/2017/08/cropped-codemanship3_twitter_avatar.jpg?w=150 3x, https://codemanship.wordpress.com/wp-content/uploads/2017/08/cropped-codemanship3_twitter_avatar.jpg?w=200 4x" class="avatar avatar-50" height="50" width="50"&gt;				Codemanship's Blog			&lt;/a&gt;
		&lt;/li&gt;
								&lt;li class="actnbr-folded-follow"&gt;
										&lt;a class="actnbr-action actnbr-actn-follow " href=""&gt;
			&lt;svg class="gridicon" height="20" width="20" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"&gt;&lt;path clip-rule="evenodd" d="m4 4.5h12v6.5h1.5v-6.5-1.5h-1.5-12-1.5v1.5 10.5c0 1.1046.89543 2 2 2h7v-1.5h-7c-.27614 0-.5-.2239-.5-.5zm10.5 2h-9v1.5h9zm-5 3h-4v1.5h4zm3.5 1.5h-1v1h1zm-1-1.5h-1.5v1.5 1 1.5h1.5 1 1.5v-1.5-1-1.5h-1.5zm-2.5 2.5h-4v1.5h4zm6.5 1.25h1.5v2.25h2.25v1.5h-2.25v2.25h-1.5v-2.25h-2.25v-1.5h2.25z" fill-rule="evenodd"&gt;&lt;/path&gt;&lt;/svg&gt;
			&lt;span&gt;Subscribe&lt;/span&gt;
		&lt;/a&gt;
		&lt;a class="actnbr-action actnbr-actn-following  no-display" href=""&gt;
			&lt;svg class="gridicon" height="20" width="20" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="none"&gt;&lt;path fill-rule="evenodd" clip-rule="evenodd" d="M16 4.5H4V15C4 15.2761 4.22386 15.5 4.5 15.5H11.5V17H4.5C3.39543 17 2.5 16.1046 2.5 15V3H17.5V12.5H16V4.5ZM5.5 6.5H14.5V8H5.5V6.5ZM5.5 9.5H9.5V11H5.5V9.5ZM12 11H13V12H12V11ZM10.5 9.5H14.5V13.5H10.5V9.5ZM5.5 12H9.5V13.5H5.5V12Z" fill="#008A20"&gt;&lt;/path&gt;&lt;path d="M19.5303 15.0303L15.5 19.0605L12.9697 16.5303L14.0303 15.4697L15.5 16.9395L18.4697 13.9697L19.5303 15.0303Z" fill="#008A20"&gt;&lt;/path&gt;&lt;/svg&gt;
			&lt;span&gt;Subscribed&lt;/span&gt;
		&lt;/a&gt;
								&lt;/li&gt;
														&lt;li class="actnbr-signup"&gt;&lt;a href="https://wordpress.com/start/"&gt;Sign up&lt;/a&gt;&lt;/li&gt;
							&lt;li class="actnbr-login"&gt;&lt;a href="https://wordpress.com/log-in?redirect_to=https%3A%2F%2Fcodemanship.wordpress.com%2F2026%2F08%2F12%2Fai-software-development-what-does-the-data-say%2F&amp;amp;signup_flow=account"&gt;Log in&lt;/a&gt;&lt;/li&gt;
																&lt;li class="actnbr-shortlink"&gt;
										&lt;a href="https://wp.me/p114rL-1e7"&gt;
											&lt;span class="actnbr-shortlink__text"&gt;Copy shortlink&lt;/span&gt;
											&lt;span class="actnbr-shortlink__icon"&gt;&lt;svg class="gridicon gridicons-checkmark" height="16" width="16" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&gt;&lt;g&gt;&lt;path d="M9 19.414l-6.707-6.707 1.414-1.414L9 16.586 20.293 5.293l1.414 1.414"&gt;&lt;/path&gt;&lt;/g&gt;&lt;/svg&gt;&lt;/span&gt;
										&lt;/a&gt;
									&lt;/li&gt;
																&lt;li class="flb-report"&gt;
									&lt;a href="https://wordpress.com/abuse/?report_url=https://codemanship.wordpress.com/2026/08/12/ai-software-development-what-does-the-data-say/" target="_blank" rel="noopener noreferrer"&gt;
										Report this content									&lt;/a&gt;
								&lt;/li&gt;
															&lt;li class="actnbr-reader"&gt;
									&lt;a href="https://wordpress.com/reader/blogs/15031761/posts/4719"&gt;
										View post in Reader									&lt;/a&gt;
								&lt;/li&gt;
															&lt;li class="actnbr-subs"&gt;
									&lt;a href="https://subscribe.wordpress.com/"&gt;Manage subscriptions&lt;/a&gt;
								&lt;/li&gt;
																&lt;li class="actnbr-fold"&gt;&lt;a href=""&gt;Collapse this bar&lt;/a&gt;&lt;/li&gt;
														&lt;/ul&gt;
					&lt;/div&gt;
				&lt;/div&gt;
			&lt;/li&gt;
		&lt;/ul&gt;
	&lt;/div&gt;
	
&lt;script&gt;
window.addEventListener( "DOMContentLoaded", function( event ) {
	var link = document.createElement( "link" );
	link.href = "/wp-content/mu-plugins/actionbar/actionbar.css?v=20250116";
	link.type = "text/css";
	link.rel = "stylesheet";
	document.head.appendChild( link );

	var script = document.createElement( "script" );
	script.src = "/wp-content/mu-plugins/actionbar/actionbar.js?v=20250204";
	document.body.appendChild( script );
} );
&lt;/script&gt;

	
	&lt;script type="text/javascript"&gt;
		window.WPCOM_sharing_counts = {"https://codemanship.wordpress.com/2026/08/12/ai-software-development-what-does-the-data-say/":4719};
	&lt;/script&gt;
				
	&lt;script type="text/javascript"&gt;
		(function () {
			var wpcom_reblog = {
				source: 'toolbar',

				toggle_reblog_box_flair: function (obj_id, post_id) {

					// Go to site selector. This will redirect to their blog if they only have one.
					const postEndpoint = `https://wordpress.com/post`;

					// Ideally we would use the permalink here, but fortunately this will be replaced with the 
					// post permalink in the editor.
					const originalURL = `${ document.location.href }?page_id=${ post_id }`; 
					
					const url =
						postEndpoint +
						'?url=' +
						encodeURIComponent( originalURL ) +
						'&amp;is_post_share=true' +
						'&amp;v=5';

					const redirect = function () {
						if (
							! window.open( url, '_blank' )
						) {
							location.href = url;
						}
					};

					if ( /Firefox/.test( navigator.userAgent ) ) {
						setTimeout( redirect, 0 );
					} else {
						redirect();
					}
				},
			};

			window.wpcom_reblog = wpcom_reblog;
		})();
	&lt;/script&gt;
&lt;script crossorigin="anonymous" type="text/javascript" src="/wp-content/mu-plugins/likes/queuehandler.js?m=1741961244i"&gt;&lt;/script&gt;
&lt;script id="wp-hooks-js" src="/wp-content/plugins/gutenberg-core/v23.7.1/build/scripts/hooks/index.min.js?m=1786118922i&amp;amp;ver=7496969728ca0f95732d"&gt;&lt;/script&gt;
&lt;script id="wp-i18n-js" src="/wp-content/plugins/gutenberg-core/v23.7.1/build/scripts/i18n/index.min.js?m=1786118922i&amp;amp;ver=125448662852c5e18937"&gt;&lt;/script&gt;
&lt;script id="wp-i18n-js-after"&gt;
wp.i18n.setLocaleData( { 'text direction\u0004ltr': [ 'ltr' ] } );
//# sourceURL=wp-i18n-js-after
&lt;/script&gt;
&lt;script id="verbum-settings-js-before"&gt;
window.VerbumComments = {"Log in or provide your name and email to leave a reply.":"Log in or provide your name and email to leave a reply.","Log in or provide your name and email to leave a comment.":"Log in or provide your name and email to leave a comment.","Receive web and mobile notifications for posts on this site.":"Receive web and mobile notifications for posts on this site.","Name":"Name","Email (address never made public)":"Email (address never made public)","Website (optional)":"Website (optional)","Leave a reply. (log in optional)":"Leave a reply. (log in optional)","Leave a comment. (log in optional)":"Leave a comment. (log in optional)","Log in to leave a reply.":"Log in to leave a reply.","Log in to leave a comment.":"Log in to leave a comment.","Logged in via %s":"Logged in via %s","Log out":"Log out","Your browser is blocking the cookies needed to log in and comment here. Allow cookies in your privacy settings, then reload the page.":"Your browser is blocking the cookies needed to log in and comment here. Allow cookies in your privacy settings, then reload the page.","Email":"Email","(Address never made public)":"(Address never made public)","Instantly":"Instantly","Daily":"Daily","Reply":"Reply","Comment":"Comment","WordPress":"WordPress","Weekly":"Weekly","Notify me of new posts":"Notify me of new posts","Email me new posts":"Email me new posts","Email me new comments":"Email me new comments","Cancel":"Cancel","Write a comment...":"Write a comment...","Write a reply...":"Write a reply...","Website":"Website","Optional":"Optional","We'll keep you in the loop!":"We'll keep you in the loop!","Loading your comment...":"Loading your comment...","Discover more from":"Discover more from Codemanship's Blog","Subscribe now to keep reading and get access to the full archive.":"Subscribe now to keep reading and get access to the full archive.","Continue reading":"Continue reading","Never miss a beat!":"Never miss a beat!","Interested in getting blog post updates? Simply click the button below to stay in the loop!":"Interested in getting blog post updates? Simply click the button below to stay in the loop!","Enter your email address":"Enter your email address","Subscribe":"Subscribe","Comment sent successfully":"Comment sent successfully","Save my name, email, and website in this browser for the next time I comment.":"Save my name, email, and website in this browser for the next time I comment.","hovercardi18n":{"Edit your profile \u2192":"Edit your profile \u2192","View profile \u2192":"View profile \u2192","Contact":"Contact","Send money":"Send money","Gravatar not found.":"Gravatar not found.","This profile is private.":"This profile is private.","Too Many Requests.":"Too Many Requests.","Internal Server Error.":"Internal Server Error.","Sorry, we are unable to load this Gravatar profile.":"Sorry, we are unable to load this Gravatar profile."},"siteId":15031761,"postId":4719,"mustLogIn":false,"requireNameEmail":true,"commentRegistration":false,"connectURL":"https://codemanship.wordpress.com/public.api/connect/?action=request\u0026from_comments=yes","logoutURL":"https://codemanship.wordpress.com/wp-login.php?action=logout\u0026_wpnonce=530c037544","homeURL":"https://codemanship.wordpress.com/","subscribeToBlog":true,"subscribeToComment":true,"isJetpackCommentsLoggedIn":false,"jetpackUsername":"","jetpackUserId":0,"jetpackSignature":"","jetpackAvatar":"https://0.gravatar.com/avatar/?s=96\u0026amp;d=identicon\u0026amp;r=G","enableBlocks":true,"enableSubscriptionModal":true,"currentLocale":"en","isJetpackComments":false,"allowedBlocks":["core/paragraph","core/list","core/code","core/list-item","core/quote","core/image","core/embed","core/quote","core/code"],"embedNonce":"43382505bf","verbumBundleUrl":"/wp-content/mu-plugins/jetpack-mu-wpcom-plugin/moon/jetpack_vendor/automattic/jetpack-mu-wpcom/src/features/verbum-comments/dist/index.js","isRTL":false,"vbeCacheBuster":1771405207,"iframeUniqueId":0,"colorScheme":false}
//# sourceURL=verbum-settings-js-before
&lt;/script&gt;
&lt;script data-wp-strategy="defer" defer="" id="verbum-dynamic-loader-js" src="/wp-content/mu-plugins/jetpack-mu-wpcom-plugin/moon/jetpack_vendor/automattic/jetpack-mu-wpcom/src/build/verbum-comments/assets/dynamic-loader.js?m=1772518873i&amp;amp;minify=false&amp;amp;ver=8b5296f9195db92c42e4"&gt;&lt;/script&gt;
&lt;script id="twentysixteen-script-js-extra"&gt;
var screenReaderText = {"expand":"expand child menu","collapse":"collapse child menu"};
//# sourceURL=twentysixteen-script-js-extra
&lt;/script&gt;
&lt;script id="jetpack-script-data-js-before"&gt;
window.JetpackScriptData = {"site":{"host":"wpcom","is_wpcom_platform":true}};
//# sourceURL=jetpack-script-data-js-before
&lt;/script&gt;
&lt;script id="jetpack-blocks-assets-base-url-js-before"&gt;
var Jetpack_Block_Assets_Base_Url="https://s0.wp.com/wp-content/mu-plugins/jetpack-plugin/moon/_inc/blocks/";
//# sourceURL=jetpack-blocks-assets-base-url-js-before
&lt;/script&gt;
&lt;script crossorigin="anonymous" type="text/javascript" src="/_static/??-eJyNj9FOwzAMRX8I16BpQB8QnzJliQtuEyeqnXX7eyzE+sAD4vX4Hh0ZtwaxipEY2icVUmz9jLY5uClfjUhwVtSFG2SWBaYau8LE12HWB3SdJeaeXPRZrKW4CSu1fBsKy330n8bUJRpX0d9S6dBy/2DxBlkLcQFHW/PazwFLrXI/ni4kqa4YutUSzDjuWlAlUzx3zmmHGlduBilY+KMcFtZCBofhEU/+8w6m9Xuc3H0vb08vr8fxMB7H5/kLh6CChg=="&gt;&lt;/script&gt;
&lt;script id="wp-dom-ready-js" src="/wp-content/plugins/gutenberg-core/v23.7.1/build/scripts/dom-ready/index.min.js?m=1786118922i&amp;amp;ver=a06281ae5cf5500e9317"&gt;&lt;/script&gt;
&lt;script crossorigin="anonymous" type="text/javascript" src="/wp-includes/js/dist/vendor/wp-polyfill.min.js?m=1786440387i"&gt;&lt;/script&gt;
&lt;script data-wp-strategy="defer" defer="" id="jetpack-block-subscriptions-js" src="/wp-content/mu-plugins/jetpack-plugin/moon/_inc/blocks/subscriptions/view.js?m=1782389597i&amp;amp;minify=false&amp;amp;ver=16.2-a.0"&gt;&lt;/script&gt;
&lt;script id="sharing-js-js-extra"&gt;
var sharing_js_options = {"lang":"en","counts":"1","is_stats_active":"1"};
//# sourceURL=sharing-js-js-extra
&lt;/script&gt;
&lt;script crossorigin="anonymous" type="text/javascript" src="/wp-content/mu-plugins/jetpack-plugin/moon/_inc/build/sharedaddy/sharing.min.js?m=1755006225i"&gt;&lt;/script&gt;
&lt;script id="sharing-js-js-after"&gt;
var windowOpen;
			( function () {
				function matches( el, sel ) {
					return !! (
						el.matches &amp;&amp; el.matches( sel ) ||
						el.msMatchesSelector &amp;&amp; el.msMatchesSelector( sel )
					);
				}

				document.body.addEventListener( 'click', function ( event ) {
					if ( ! event.target ) {
						return;
					}

					var el;
					if ( matches( event.target, 'a.share-twitter' ) ) {
						el = event.target;
					} else if ( event.target.parentNode &amp;&amp; matches( event.target.parentNode, 'a.share-twitter' ) ) {
						el = event.target.parentNode;
					}

					if ( el ) {
						event.preventDefault();

						// If there's another sharing window open, close it.
						if ( typeof windowOpen !== 'undefined' ) {
							windowOpen.close();
						}
						windowOpen = window.open( el.getAttribute( 'href' ), 'wpcomtwitter', 'menubar=1,resizable=1,width=600,height=350' );
						return false;
					}
				} );
			} )();
var windowOpen;
			( function () {
				function matches( el, sel ) {
					return !! (
						el.matches &amp;&amp; el.matches( sel ) ||
						el.msMatchesSelector &amp;&amp; el.msMatchesSelector( sel )
					);
				}

				document.body.addEventListener( 'click', function ( event ) {
					if ( ! event.target ) {
						return;
					}

					var el;
					if ( matches( event.target, 'a.share-facebook' ) ) {
						el = event.target;
					} else if ( event.target.parentNode &amp;&amp; matches( event.target.parentNode, 'a.share-facebook' ) ) {
						el = event.target.parentNode;
					}

					if ( el ) {
						event.preventDefault();

						// If there's another sharing window open, close it.
						if ( typeof windowOpen !== 'undefined' ) {
							windowOpen.close();
						}
						windowOpen = window.open( el.getAttribute( 'href' ), 'wpcomfacebook', 'menubar=1,resizable=1,width=600,height=400' );
						return false;
					}
				} );
			} )();
var windowOpen;
			( function () {
				function matches( el, sel ) {
					return !! (
						el.matches &amp;&amp; el.matches( sel ) ||
						el.msMatchesSelector &amp;&amp; el.msMatchesSelector( sel )
					);
				}

				document.body.addEventListener( 'click', function ( event ) {
					if ( ! event.target ) {
						return;
					}

					var el;
					if ( matches( event.target, 'a.share-linkedin' ) ) {
						el = event.target;
					} else if ( event.target.parentNode &amp;&amp; matches( event.target.parentNode, 'a.share-linkedin' ) ) {
						el = event.target.parentNode;
					}

					if ( el ) {
						event.preventDefault();

						// If there's another sharing window open, close it.
						if ( typeof windowOpen !== 'undefined' ) {
							windowOpen.close();
						}
						windowOpen = window.open( el.getAttribute( 'href' ), 'wpcomlinkedin', 'menubar=1,resizable=1,width=580,height=450' );
						return false;
					}
				} );
			} )();
//# sourceURL=sharing-js-js-after
&lt;/script&gt;
&lt;script id="wp-emoji-settings" type="application/json"&gt;
{"baseUrl":"https://s0.wp.com/wp-content/mu-plugins/wpcom-smileys/twemoji/2/72x72/","ext":".png","svgUrl":"https://s0.wp.com/wp-content/mu-plugins/wpcom-smileys/twemoji/2/svg/","svgExt":".svg","source":{"concatemoji":"/wp-includes/js/wp-emoji-release.min.js?m=1783090810i&amp;ver=7.1-alpha-62686"}}
&lt;/script&gt;
&lt;script type="module"&gt;
/*! This file is auto-generated */
var e="script#wp-emoji-settings",t=document.querySelector(e);if(!(t instanceof HTMLScriptElement))throw new Error("Element missing: "+e);const r=JSON.parse(t.text),s=(window._wpemojiSettings=r,"wpEmojiSettingsSupports"),o=["flag","emoji"];function i(e){try{var t={supportTests:e,timestamp:(new Date).valueOf()};sessionStorage.setItem(s,JSON.stringify(t))}catch(e){}}function c(e,t,n){e.clearRect(0,0,e.canvas.width,e.canvas.height),e.fillText(t,0,0);t=new Uint32Array(e.getImageData(0,0,e.canvas.width,e.canvas.height).data);e.clearRect(0,0,e.canvas.width,e.canvas.height),e.fillText(n,0,0);const r=new Uint32Array(e.getImageData(0,0,e.canvas.width,e.canvas.height).data);return t.every((e,t)=&gt;e===r[t])}function p(e,t){e.clearRect(0,0,e.canvas.width,e.canvas.height),e.fillText(t,0,0);var n=e.getImageData(16,16,1,1);for(let e=0;e&lt;n.data.length;e++)if(0!==n.data[e])return!1;return!0}function u(e,t,n,r){switch(t){case"flag":return n(e,"\ud83c\udff3\ufe0f\u200d\u26a7\ufe0f","\ud83c\udff3\ufe0f\u200b\u26a7\ufe0f")?!1:!n(e,"\ud83c\udde8\ud83c\uddf6","\ud83c\udde8\u200b\ud83c\uddf6")&amp;&amp;!n(e,"\ud83c\udff4\udb40\udc67\udb40\udc62\udb40\udc65\udb40\udc6e\udb40\udc67\udb40\udc7f","\ud83c\udff4\u200b\udb40\udc67\u200b\udb40\udc62\u200b\udb40\udc65\u200b\udb40\udc6e\u200b\udb40\udc67\u200b\udb40\udc7f");case"emoji":return!r(e,"\ud83e\u1fac8")}return!1}function f(e,t,n,r){let a;const s=(a="undefined"!=typeof WorkerGlobalScope&amp;&amp;self instanceof WorkerGlobalScope?new OffscreenCanvas(300,150):document.createElement("canvas")).getContext("2d",{willReadFrequently:!0}),o=(s.textBaseline="top",s.font="600 32px Arial",{});return e.forEach(e=&gt;{o[e]=t(s,e,n,r)}),o}function a(e){var t=document.createElement("script");t.src=e,t.defer=!0,document.head.appendChild(t)}r.supports={everything:!0,everythingExceptFlag:!0},new Promise(t=&gt;{let n=function(){try{var e=JSON.parse(sessionStorage.getItem(s));if("object"==typeof e&amp;&amp;"number"==typeof e.timestamp&amp;&amp;(new Date).valueOf()&lt;e.timestamp+604800&amp;&amp;"object"==typeof e.supportTests)return e.supportTests}catch(e){}return null}();if(!n){if("undefined"!=typeof Worker&amp;&amp;"undefined"!=typeof OffscreenCanvas&amp;&amp;"undefined"!=typeof URL&amp;&amp;URL.createObjectURL&amp;&amp;"undefined"!=typeof Blob)try{var e="postMessage("+f.toString()+"("+[JSON.stringify(o),u.toString(),c.toString(),p.toString()].join(",")+"));",r=new Blob([e],{type:"text/javascript"});const a=new Worker(URL.createObjectURL(r),{name:"wpTestEmojiSupports"});return void(a.onmessage=e=&gt;{i(n=e.data),a.terminate(),t(n)})}catch(e){}i(n=f(o,u,c,p))}t(n)}).then(e=&gt;{for(const n in e)r.supports[n]=e[n],r.supports.everything=r.supports.everything&amp;&amp;r.supports[n],"flag"!==n&amp;&amp;(r.supports.everythingExceptFlag=r.supports.everythingExceptFlag&amp;&amp;r.supports[n]);var t;r.supports.everythingExceptFlag=r.supports.everythingExceptFlag&amp;&amp;!r.supports.flag,r.supports.everything||((t=r.source||{}).concatemoji?a(t.concatemoji):t.wpemoji&amp;&amp;t.twemoji&amp;&amp;(a(t.twemoji),a(t.wpemoji)))});
//# sourceURL=/wp-includes/js/wp-emoji-loader.min.js
&lt;/script&gt;
	&lt;iframe src="https://widgets.wp.com/likes/master.html?ver=20260812#ver=20260812" scrolling="no" id="likes-master" name="likes-master" style="display:none;"&gt;&lt;/iframe&gt;
	&lt;div id="likes-other-gravatars" role="dialog" aria-hidden="true" tabindex="-1"&gt;&lt;div class="likes-text"&gt;&lt;span&gt;%d&lt;/span&gt;&lt;/div&gt;&lt;ul class="wpl-avatars sd-like-gravatars"&gt;&lt;/ul&gt;&lt;/div&gt;
	&lt;script src="//stats.wp.com/w.js?69" defer=""&gt;&lt;/script&gt; &lt;script type="text/javascript"&gt;
_tkq = window._tkq || [];
_stq = window._stq || [];
_tkq.push(['storeContext', {'blog_id':'15031761','blog_tz':'1','user_lang':'en','blog_lang':'en','user_id':'0'}]);
		// Prevent sending pageview tracking from WP-Admin pages.
		_stq.push(['view', {'blog':'15031761','v':'wpcom','tz':'1','user_id':'0','post':'4719','subd':'codemanship'}]);
		_stq.push(['extra', {'crypt':'UE5tW3cvZGQ/JUs1UEo9WXFZM2k9fDlzc2JWP3hETzFRNDFNOT11fjNqYVJdS3BRJnMxSTNjVkF4Z3QwRS95dHdsZFNVZS40fF1iOS4zWGNiSi8vU1FpWnFQMTloOC9uY1Y1aiZDX3wwW01zVHR1WzFhQ19sPVFNNldtUVRPJUhPaF1EVzNLSiwwMSUsT1NdbjdZTSx+cWp4emg/LzlNdy1XSC1FU2FRP2IyZ0ptVEZLQkksaGViZUpPeTl4UDRCcFZJVE9K'}]);
_stq.push([ 'clickTrackerInit', '15031761', '4719' ]);
&lt;/script&gt;
&lt;noscript&gt;&lt;img src="https://pixel.wp.com/b.gif?v=noscript" style="height:1px;width:1px;overflow:hidden;position:absolute;bottom:1px;" alt="" /&gt;&lt;/noscript&gt;
&lt;meta id="bilmur" property="bilmur:data" content="" data-provider="wordpress.com" data-service="simple" data-site-tz="Europe/London" data-custom-props="{&amp;quot;enq_wp-polyfill&amp;quot;:&amp;quot;1&amp;quot;,&amp;quot;logged_in&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;wptheme&amp;quot;:&amp;quot;pub\/twentysixteen&amp;quot;,&amp;quot;wptheme_is_block&amp;quot;:&amp;quot;0&amp;quot;}"&gt;
		&lt;script defer="" src="/wp-content/js/bilmur.min.js?i=17&amp;amp;m=202633"&gt;&lt;/script&gt; 	
&lt;script&gt;
(function() {
	'use strict';

	const fetches = {};
	const promises = {};
	const urls = {
		'verbum': '/wp-content/mu-plugins/jetpack-mu-wpcom-plugin/moon/jetpack_vendor/automattic/jetpack-mu-wpcom/src/build/verbum-comments/verbum-comments.js?m=1785895867i&amp;minify=false&amp;ver=ecf5cfe8827907d3ea28'
	};
	const loaders = {
		'verbum': () =&gt; {
			fetchExternalScript('verbum');
			promises['verbum'] = promises['verbum'] || loadWPScript('verbum');
			return promises['verbum'];
		},
		
	};
	const scriptExtras = {
		
	};

	window.WP_Enqueue_Dynamic_Script = {
		loadScript: (handle) =&gt; {
			if (!loaders[handle]) {
				console.error('WP_Enqueue_Dynamic_Script: unregistered script `' + handle + '`.');
			}
			return loaders[handle]();
		}
	};

	function fetchExternalScript(handle) {
		if (!urls[handle]) {
			return Promise.resolve();
		}

		fetches[handle] = fetches[handle] || fetch(urls[handle], { mode: 'no-cors' });
		return fetches[handle];
	}

	function runExtraScript(handle, type, index) {
		const id = 'wp-enqueue-dynamic-script:' + handle + ':' + type + ':' + (index + 1);
		const template = document.getElementById(id);
		if (!template) {
			return Promise.reject();
		}

		const script = document.createElement( 'script' );
		script.innerHTML = template.innerHTML;
		document.body.appendChild( script );
		return Promise.resolve();
	}

	function loadExternalScript(handle) {
		if (!urls[handle]) {
			return Promise.resolve();
		}

		return fetches[handle].then(() =&gt; {
			return new Promise((resolve, reject) =&gt; {
				const script = document.createElement('script');
				script.onload = () =&gt; resolve();
				script.onerror = (e) =&gt; reject(e);
				script.src = urls[handle];
				document.body.appendChild(script);
			});
		});
	}

	function loadExtra(handle, pos) {
		const count = (scriptExtras[handle] &amp;&amp; scriptExtras[handle][pos]) || 0;
		let promise = Promise.resolve();

		for (let i = 0; i &lt; count; i++) {
			promise = promise.then(() =&gt; runExtraScript(handle, pos, i));
		}

		return promise;
	}

	function loadWPScript(handle) {
		// Core loads scripts in this order. See: https://github.com/WordPress/WordPress/blob/a59eb9d39c4fcba834b70c9e8dfd64feeec10ba6/wp-includes/class-wp-scripts.php#L428.
		return loadExtra(handle, 'translations')
			.then(() =&gt; loadExtra(handle, 'before'))
			.then(() =&gt; loadExternalScript(handle))
			.then(() =&gt; loadExtra(handle, 'after'));
	}
} )();
&lt;/script&gt;



&lt;style&gt;img#wpstats {
			position: absolute !important;
			clip: rect(0, 0, 0, 0);
			padding: 0 !important;
			border: 0 !important;
			height: 0 !important;
			width: 0 !important;
			overflow: hidden;
		}&lt;/style&gt;&lt;img src="https://pixel.wp.com/g.gif?blog=15031761&amp;amp;v=wpcom&amp;amp;tz=1&amp;amp;user_id=0&amp;amp;post=4719&amp;amp;subd=codemanship&amp;amp;host=codemanship.wordpress.com&amp;amp;ref=https%3A%2F%2Fgo.bsky.app%2F&amp;amp;rand=0.4942255589579757" alt="" id="wpstats"&gt;&lt;script src="/wp-content/mu-plugins/actionbar/actionbar.js?v=20250204"&gt;&lt;/script&gt;&lt;/body&gt;&lt;/html&gt;</content>
        <author>
            <name>View all posts by codemanship</name>
        </author>
        <media:content medium="image" url="https://i0.wp.com/codemanship.wordpress.com/wp-content/uploads/2026/08/evidence.png?fit=1200%2C675&amp;ssl=1&amp;w=640"/>
        <link href="https://i0.wp.com/codemanship.wordpress.com/wp-content/uploads/2026/08/evidence.png?fit=1200%2C675&amp;ssl=1" rel="enclosure" type="image/png"/>
        <source>
            <id>tag:feedly.com,2013:cloud/feed/https://codemanship.wordpress.com/feed/</id>
            <title type="html">Codemanship's Blog</title>
            <link href="https://codemanship.wordpress.com" rel="alternate" type="text/html"/>
            <updated>2026-08-12T19:34:25Z</updated>
        </source>
    </entry>
    <entry>
        <id>tag:feedly.com,2013:cloud/entry/cOXRjoksGIQzU1pdqbdybn+OTWYeI0riptNneGckdsI=_19feafa1f4a:6eca0d:2eb0c877</id>
        <title type="html">Cloudflare OS is an architecture of distrust</title>
        <published>2026-08-10T09:21:28Z</published>
        <updated>2026-08-10T09:21:32Z</updated>
        <link href="https://lord.technology/2026/08/05/cloudflare-os-is-an-architecture-of-distrust.html" rel="alternate" type="text/html"/>
        <summary type="html">The strangest thing in the Cloudflare OS source code took me a while to understand.</summary>
        <content type="html">&lt;!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"&gt;
&lt;html&gt;&lt;body&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;
        
        &lt;p&gt;The strangest thing in the &lt;a href="https://github.com/cloudflare/cloudflare-os"&gt;Cloudflare OS source code&lt;/a&gt; took me a while to understand.&lt;/p&gt;

&lt;p&gt;When an agent inside Cloudflare OS wants to do something with a side effect (merge a pull request, send an email, write a row to a system of record), it goes through a Gatekeeper, a small service that holds the credential and mediates the action. So far, that’s just a well-built MCP server. But read the contract a Gatekeeper is written against (&lt;code&gt;packages/workshop-shared/src/gatekeeper.ts&lt;/code&gt;, &lt;a href="https://github.com/cloudflare/cloudflare-os/blob/e1ab8fbd4f609aff7ede9d490bafe1bcf9b2a682/packages/workshop-shared/src/gatekeeper.ts#L617"&gt;around line 617&lt;/a&gt;) and you find this instruction to the author:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;It is suggested that the gatekeeper “simulate” actions that have not been approved yet, that is, the &lt;code&gt;Session&lt;/code&gt; interface should reflect the state of the resource as if all actions had been applied.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Sit with that. The agent asks to merge the PR. The human hasn’t approved it. So the Gatekeeper tells the agent the PR is merged, and if the agent reads the branch back to check its work, hands it a fabricated reality in which the merge happened. The agent, satisfied, queues the next three steps that depend on it. None of it is real. Later a human looks at the batch and either commits it or bins it, and if they bin it, everything the agent built on the fiction goes too.&lt;/p&gt;

&lt;p&gt;The first time I traced this I thought it was a hack. It’s the philosophy of the whole system, compressed into one method signature. The Gatekeeper lies to the agent on purpose, because the alternative (letting an agent’s actions touch the world the moment it decides to take them) assumes the agent’s decisions are sound. Cloudflare OS is built from end to end on the assumption that they are not.&lt;/p&gt;

&lt;p&gt;The name is a distraction, so set it aside. The Hacker News thread spent most of its energy arguing about whether “OS” is a permitted word for the thing, and that’s a dead end. What’s actually interesting is that a team led by Kenton Varda, the people who built the Workers runtime, sat down to design a platform for AI agents doing real work inside a company, and the organising principle they landed on was this: the agent cannot be trusted, so build so that its mistakes cannot matter. Every load-bearing part of the system is a variation on that sentence.&lt;/p&gt;

&lt;p&gt;Last week I &lt;a href="https://lord.technology/2026/07/29/opus-5-gets-things-wrong-more-quietly.html"&gt;wrote about Opus 5&lt;/a&gt; getting things confidently, quietly wrong: shipping a change that reported success while doing the opposite, caught only on a second pass. This is what it looks like to take that failure mode not as a grievance but as a permanent design constraint, and pour concrete on top of it.&lt;/p&gt;

&lt;h2 id="make-the-code-irrelevant-to-safety"&gt;Make the code irrelevant to safety&lt;/h2&gt;

&lt;p&gt;Start with the sandbox, because everything else stands on it.&lt;/p&gt;

&lt;p&gt;When you make a slide deck in Cloudflare OS, you aren’t using one shared slide-deck app. The system spins up a private instance of the slide-deck code, a “gadget”, that belongs only to you. It runs in its own Dynamic Worker, with its own SQLite database behind a Durable Object Facet, outbound networking switched off. Every document is its own sandboxed process.&lt;/p&gt;

&lt;p&gt;This is Sandstorm, Kenton’s startup from a decade ago, reborn. What Sandstorm got right and could never make cheap was fine-grained instancing: every document in its own isolation boundary. Containers made that far too expensive, seconds of cold start and hundreds of megabytes per grain, so the idea sat on a shelf for ten years until V8 isolates made it roughly a hundred times cheaper to run. I wrote &lt;a href="https://architectingoncloudflare.com/"&gt;a book about this platform&lt;/a&gt; and called Durable Objects its most underappreciated primitive; the thing they were waiting to enable, it turns out, was this.&lt;/p&gt;

&lt;p&gt;Per-document instancing changes where security lives. For twenty-five years the boundary in multi-tenant SaaS has run straight through the application code. One shared service holds everyone’s data, and a single mistake in a &lt;code&gt;WHERE&lt;/code&gt; clause, one missing &lt;code&gt;tenant_id&lt;/code&gt;, leaks customer B’s records to customer A. The code is load-bearing for security. It has to be correct, and a junior engineer’s off-day is a breach.&lt;/p&gt;

&lt;p&gt;Cloudflare OS moves the boundary out of the code and into the platform. If every user has their own instance, and the platform controls who can reach an instance at all, a bug in the gadget can only hurt the one person who owns it. Kenton puts it flatly: the AI cannot introduce a significant security bug. He’s right, in the sense that matters. A gadget can’t leak to another user however badly it’s written, because there is no other user in its sandbox to leak to.&lt;/p&gt;

&lt;p&gt;This is the first and boldest act of distrust. They didn’t make the AI’s code trustworthy. They gave up on that and made it irrelevant, arranging things so the correctness of what the agent writes is no longer a security property at all. You can let a non-technical colleague vibe-code an app and share it, and the reason the security team sleeps is not that the app is good. It’s that a bad app can’t reach them.&lt;/p&gt;

&lt;h2 id="never-let-the-agent-hold-the-key"&gt;Never let the agent hold the key&lt;/h2&gt;

&lt;p&gt;The cleverest move is the quiet one.&lt;/p&gt;

&lt;p&gt;The obvious way to give an agent access to GitHub is to give it a GitHub token. Anyone who has wired up an MCP server has done some version of this, and felt the small cold moment of realising a token in a prompt can end up anywhere the prompt’s output goes.&lt;/p&gt;

&lt;p&gt;Cloudflare OS never gives the agent the credential. The Gatekeeper holds it. What the agent gets is a capability: in the generated code it appears as a binding, &lt;code&gt;env.PROJECT&lt;/code&gt;, an object it can call methods on. Not the key itself, but permission to perform a specific, narrowed set of operations the Gatekeeper will carry out on its behalf. Give the GitHub Gatekeeper a single repository and it can let the agent read issues but not source, mask fields, refuse to merge without approval. The agent can call &lt;code&gt;listIssues()&lt;/code&gt;. It cannot see the token, widen its own access, or reach the network except through capabilities it was explicitly handed.&lt;/p&gt;

&lt;p&gt;None of this is theoretical to me. I built exactly this credential-broker pattern for CDS, and it has since rolled out across the engineering practice there: the broker holds the secret, the agent gets a handle and never the key itself.&lt;/p&gt;

&lt;p&gt;This is the object-capability model, and it isn’t decoration. It’s the Cap’n Proto lineage Sandstorm was built on, resurfacing as Cap’n Web RPC, because a capability is the only kind of authority you can safely hand an actor you’ve decided not to trust. A key is bearer authority: whoever holds it wields it. A capability is a leash. It does one thing, it can be revoked, it stays attached to whatever granted it. If your agent might be confidently wrong, or prompt-injected, or just careless about what it writes into an app’s source, the credential is the one thing it must never touch. So it never touches it.&lt;/p&gt;

&lt;h2 id="let-it-act-but-never-let-it-commit"&gt;Let it act, but never let it commit&lt;/h2&gt;

&lt;p&gt;Now the simulated merge from the opening makes sense: the same idea, moved from access into control flow.&lt;/p&gt;

&lt;p&gt;The problem it solves is one I’ve felt every day for a year. Synchronous approval is miserable. The agent stops on step one, you’ve wandered off to make coffee, you come back to no progress. So people cave and turn on auto-approve, or &lt;code&gt;--dangerously-skip-permissions&lt;/code&gt;, and the safety mechanism they installed to sleep at night is the first thing they switch off to get anything done.&lt;/p&gt;

&lt;p&gt;Cloudflare OS splits acting from committing. Reads flow: a read is authorised against the capability and recorded, but it doesn’t stop for a human. Writes are provisional. The Gatekeeper accepts the action, simulates the result, and lets the agent race ahead building whatever depends on it, while the real effect sits in a queue for a person to release in a batch, later, when it suits them. The agent gets the throughput of auto-approve; the human keeps the veto of manual review. The human is no longer an interruption in the loop. The human is the commit.&lt;/p&gt;

&lt;p&gt;It’s optimistic concurrency for actions in the real world, with a person as the transaction monitor, and it has the property optimistic concurrency always has: the agent spends part of its life operating on a state that isn’t true yet and may never be. It reads back its own un-happened writes and reasons about them. The architecture’s answer to “isn’t that dangerous?” is a shrug. It doesn’t matter what the agent believes about a world no human has ratified. Belief is free. Only the commit is real, and the agent doesn’t hold the commit.&lt;/p&gt;

&lt;h2 id="distrust-the-outputs-not-just-the-actions"&gt;Distrust the outputs, not just the actions&lt;/h2&gt;

&lt;p&gt;The subtlest move is the one &lt;a href="https://blog.cloudflare.com/cloudflare-os/"&gt;the blog post&lt;/a&gt; almost entirely hides.&lt;/p&gt;

&lt;p&gt;The first three mechanisms distrust what the agent does. This one distrusts what it produces. An agent reads a sensitive revenue table and builds a live dashboard from it. The dashboard is a new artefact with no access list of its own. Share it, and you may have just handed the table to everyone who can see the dashboard: a leak no single component did anything wrong to cause.&lt;/p&gt;

&lt;p&gt;So Cloudflare OS records every observation a gadget makes. The mechanism lives in &lt;a href="https://github.com/cloudflare/cloudflare-os/blob/e1ab8fbd4f609aff7ede9d490bafe1bcf9b2a682/docs/observers.md"&gt;&lt;code&gt;docs/observers.md&lt;/code&gt;&lt;/a&gt;, and it is, in essence, decentralised information-flow control: the academic dream of the mid-2000s, the Jif and HiStar and Flume line of work that never shipped commercially because labelling every piece of data by hand cost more than it returned. When Alice shares a gadget with Bob, every Gatekeeper the gadget has touched is asked, independently, whether Bob may directly read everything the gadget has already read through it. If he can’t, he’s refused. From then on, any new read the gadget makes that Bob isn’t cleared for is blocked outright.&lt;/p&gt;

&lt;p&gt;The detail I keep turning over is that the kernel refuses to understand identity. The overseer, the “kernel” in the repo’s own OS analogy, does not know what a GitHub user is, or a Google user, or what any vendor’s permissions mean. It hands each Gatekeeper an opaque token minted by the observer’s own account and lets the Gatekeeper be the sole authority on its own resource. The code goes out of its way to make that handle a random string, so no Gatekeeper author is tempted to parse identity out of it. Authority is decentralised on purpose. The centre is built to know as little as it can.&lt;/p&gt;

&lt;p&gt;Where the policy engine can’t yet express the nuance, it falls back to raw distrust. A flag, &lt;code&gt;prohibitAllSharing&lt;/code&gt;, marks data so sensitive it must never leave the owner. Once a gadget reads something wearing that flag, it drops into “lockdown mode”: it can still read, but it can no longer take a single action, through any Gatekeeper, ever, in case the action is what smuggles the secret out. A taint bit. A one-way door. The bluntest instrument available, and the comment above it says so and calls it a stopgap. What DIFC never had a good enough reason to ship for, an autonomous agent supplies: you cannot hand-audit what a thing read when it reads a thousand times an hour and reasons about all of it at once.&lt;/p&gt;

&lt;h2 id="a-tell-in-the-contributing-guide"&gt;A tell in the contributing guide&lt;/h2&gt;

&lt;p&gt;The worldview surfaces in an odd place. &lt;code&gt;CONTRIBUTING.md&lt;/code&gt; asks you, politely, not to send pull requests longer than a dozen lines or so, and says why: AI has made writing code cheap, so an outside contribution donates the easy part while creating the expensive part, which is review and keeping the whole thing coherent. They would rather you didn’t.&lt;/p&gt;

&lt;p&gt;There’s a real claim buried there. The scarce resource in software has inverted. Producing code is no longer the bottleneck; vouching for it is. And it’s the same reflex as everything else in the system. An unreviewed contribution is untrusted input, and it barely matters whether a careless human or a confident model produced it: the instinct, now written into the project’s own governance, is to keep unvetted work out until someone accountable has looked at it. They’ve generalised their distrust of the agent into a distrust of the contribution, and then into a policy about you.&lt;/p&gt;

&lt;h2 id="is-this-wisdom-or-a-cage"&gt;Is this wisdom or a cage?&lt;/h2&gt;

&lt;p&gt;I’ve read a lot of agent frameworks this year, and most are optimistic in a way that embarrasses them within a month. This one isn’t, and I admire it for that. It’s the first agent platform I’ve seen that treats the failure mode as real instead of writing a longer system prompt and hoping. If you believe, as I’ve come to, that the models are confidently wrong often enough that their self-reports can’t be load-bearing, then an architecture that assumes exactly that isn’t cynicism. It’s honesty.&lt;/p&gt;

&lt;p&gt;But an architecture built on the premise that the worker can’t be trusted also caps what the worker is allowed to become. An agent that can never hold a credential can never do the job that truly needs one. A write that is always provisional means a human is always, structurally, in the loop: the precise bottleneck agents were meant to remove. Every act of distrust here is also a leash, and the leash that keeps the animal safe is the one that stops it pulling the cart very far. You can’t design for maximum autonomy and maximum containment at once. Cloudflare has chosen containment, hard, betting that a caged agent doing real work beats a free one you daren’t deploy.&lt;/p&gt;

&lt;p&gt;And there’s one thing the distrust never turns on. The agent is untrusted. The user’s code is untrusted. The human contributor is untrusted. Every principal is held at arm’s length and made to earn each move through a capability. Every principal except Cloudflare, whose primitives are the arm. The observation log, the Gatekeepers, the sandbox that makes the whole thing safe are all Workers, Durable Objects, Facets, some added to the runtime for this and existing nowhere else. It runs on &lt;code&gt;workerd&lt;/code&gt;, which is open source, and you can self-host it, which is more than most of its rivals can say. But the architecture that trusts no one rests entirely on trusting the one party that poured the ground beneath it.&lt;/p&gt;

&lt;p&gt;Last week a model told me it had fixed something, and it hadn’t, and I only found out because I went and looked. Cloudflare has built a whole operating system on the certainty that it always will (that the thing you delegate to will report a success it hasn’t earned), and then arranged matters so that when it does, a human holds the only pen that writes to the world. Whether that’s the shape of all serious agent infrastructure from here, or a very elegant set of walls we’ll spend three years learning to resent, I can’t tell. Probably both. The kernel table in the README has a row for processes, a row for users, and a row for agents left blank, marked only &lt;code&gt;???&lt;/code&gt;. They know it’s a new kind of thing. They just don’t trust it yet.&lt;/p&gt;


        
      &lt;/div&gt;
    &lt;/div&gt;&lt;/div&gt;&lt;/body&gt;&lt;/html&gt;</content>
        <author>
            <name>Jamie Lord</name>
        </author>
        <media:content medium="image" url="https://lord.technology/assets/images/og-image.png"/>
        <source>
            <id>tag:feedly.com,2013:cloud/feed/https://lord.technology/feed.xml</id>
            <title type="html">Jamie Lord</title>
            <link href="https://lord.technology" rel="alternate" type="text/html"/>
            <updated>2026-08-10T09:21:32Z</updated>
        </source>
    </entry>
    <entry>
        <id>tag:feedly.com,2013:cloud/entry/cOXRjoksGIQzU1pdqbdybn+OTWYeI0riptNneGckdsI=_19fdbe0191a:6b17df:e727fc99</id>
        <title type="html">SSD Streaming for AI Models: How to Turn RAM from a Wall into a Dial</title>
        <published>2026-08-07T10:58:44Z</published>
        <updated>2026-08-07T10:58:48Z</updated>
        <link href="https://www.mindstudio.ai/blog/ssd-streaming-ai-models-ram-dial" rel="alternate" type="text/html"/>
        <summary type="html">Dwarf Star's SSD streaming stores expert weights on disk and loads them on demand, eliminating the binary 'fits or doesn't run' problem for large local models.</summary>
        <content type="html">&lt;!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"&gt;
&lt;html&gt;&lt;body&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;section&gt;&lt;h2 id="s-1"&gt;When RAM Becomes the Bottleneck, Not the Solution&lt;/h2&gt;
&lt;p&gt;If you’ve ever tried running a large language model locally, you’ve probably hit the same wall. You find a model you want to use — maybe a Mixtral variant, a DeepSeek model, or something else with real capability — check the requirements, look at your available RAM, and discover you’re about 20GB short. The model doesn’t run at a reduced quality. It just doesn’t run.&lt;/p&gt;
&lt;p&gt;That binary outcome is the core frustration of local AI deployment. RAM has always functioned as an on/off switch: either the whole model fits, or nothing works. SSD streaming flips that logic entirely. By storing model weights on disk and loading them on demand, it turns RAM from a fixed ceiling into an adjustable dial. Dwarf Star is one of the more interesting implementations of this idea, specifically targeting the expert weights in Mixture of Experts (MoE) models.&lt;/p&gt;
&lt;p&gt;This article explains how SSD streaming works, why MoE architectures make it practical, what trade-offs you’re accepting, and who actually benefits from it.&lt;/p&gt;
&lt;hr&gt;&lt;/section&gt;&lt;section&gt;&lt;h2 id="s-2"&gt;The Real Problem with Running Large Models Locally&lt;/h2&gt;
&lt;p&gt;Most people frame the local AI problem as “my computer isn’t powerful enough.” That’s not quite right. The more precise framing is: model weights have to live somewhere your processor can access them quickly, and RAM is the fastest accessible space in that chain.&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;div&gt;
    
    &lt;h2&gt;
      &lt;span&gt;Plans first.&lt;/span&gt;
      &lt;span&gt;&lt;em&gt;Then code.&lt;/em&gt;&lt;/span&gt;
    &lt;/h2&gt;
    &lt;div&gt;
      &lt;p&gt;&lt;span&gt;PROJECT&lt;/span&gt;&lt;span&gt;YOUR APP&lt;/span&gt;&lt;/p&gt;
      &lt;p&gt;&lt;span&gt;SCREENS&lt;/span&gt;&lt;span&gt;12&lt;/span&gt;&lt;/p&gt;
      &lt;p&gt;&lt;span&gt;DB TABLES&lt;/span&gt;&lt;span&gt;6&lt;/span&gt;&lt;/p&gt;
      &lt;p&gt;&lt;span&gt;BUILT BY&lt;/span&gt;&lt;span&gt;REMY&lt;/span&gt;&lt;/p&gt;
    &lt;/div&gt;
    &lt;div&gt;
      
      &lt;span&gt;1280 px · TYP.&lt;/span&gt;
      
      &lt;span&gt;A · UI · FRONT END&lt;/span&gt;
    &lt;/div&gt;
    &lt;p&gt;Remy writes the spec, manages the build, and ships the app.&lt;/p&gt;
  &lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;When you load a model, its weights get copied into RAM. Every inference — every token generated — reads from those weights repeatedly. If the weights don’t fit in RAM, the system starts reading from swap space (disk), and inference slows to a crawl or crashes entirely.&lt;/p&gt;
&lt;p&gt;For smaller models (7B parameters, quantized), this is manageable. A 4-bit quantized 7B model runs comfortably in 6–8GB of RAM. But the models that people actually want to run locally — the ones with strong reasoning, broad knowledge, and real-world utility — tend to be 30B, 70B, or larger. A 70B model at 4-bit quantization still needs around 40GB of RAM.&lt;/p&gt;
&lt;p&gt;Most consumer machines top out at 16–32GB. That gap isn’t small.&lt;/p&gt;
&lt;h3 id="the-scale-problem-gets-worse-with-capability"&gt;The Scale Problem Gets Worse with Capability&lt;/h3&gt;
&lt;p&gt;There’s an uncomfortable relationship between model capability and size. Broadly speaking, more parameters means better performance on complex tasks. The models people reach for when they want serious results — multi-step reasoning, code generation, nuanced writing — are the ones that won’t fit.&lt;/p&gt;
&lt;p&gt;This creates a practical tiering problem. You can run the models you need for simple tasks, but the moment you need something harder, you’re looking at API calls, cloud costs, or a hardware upgrade.&lt;/p&gt;
&lt;p&gt;SSD streaming is an attempt to break that relationship by changing where model weights live, not by shrinking the model itself.&lt;/p&gt;
&lt;hr&gt;&lt;/section&gt;&lt;section&gt;&lt;h2 id="s-3"&gt;Mixture of Experts: Why Not All Weights Are Created Equal&lt;/h2&gt;
&lt;p&gt;To understand why SSD streaming is practical at all, you need to understand Mixture of Experts (MoE) architecture. It’s the key that makes on-demand weight loading viable.&lt;/p&gt;
&lt;p&gt;In a standard dense model, every layer processes every input. If a model has 70 billion parameters, all 70 billion are involved in generating each token. That’s why large dense models need so much RAM — everything has to be loaded and accessible.&lt;/p&gt;
&lt;p&gt;MoE models work differently. Instead of one large feedforward network in each layer, they have multiple smaller networks called “experts.” A routing mechanism looks at each input token and decides which experts to activate — typically just two or four out of eight, sixteen, or more available.&lt;/p&gt;
&lt;h3 id="what-this-means-practically"&gt;What This Means Practically&lt;/h3&gt;
&lt;p&gt;A model like Mixtral 8x7B has eight expert networks per layer. For any given token, only two of them fire. The other six sit idle.&lt;/p&gt;
&lt;p&gt;Total parameter count is high — around 46 billion parameters — but active parameters per forward pass are much lower, closer to 12–13 billion. That’s why MoE models can punch above their inference weight: you get the parameter breadth of a large model with the compute cost of a smaller one.&lt;/p&gt;
&lt;p&gt;But here’s the implication that makes SSD streaming interesting: if only two experts are active at any given moment, you don’t need all eight experts in RAM simultaneously. You only need the two that are about to be used.&lt;/p&gt;
&lt;p&gt;This is the architectural opening that Dwarf Star exploits.&lt;/p&gt;
&lt;hr&gt;&lt;/section&gt;&lt;section&gt;&lt;h2 id="s-4"&gt;How SSD Streaming Actually Works&lt;/h2&gt;
&lt;p&gt;The core idea is straightforward: keep the expert weights on your SSD instead of in RAM, and load them into memory only when the router selects them.&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;div&gt;
    
    &lt;p&gt;
      &lt;/p&gt;&lt;h3&gt;Everyone else built a construction worker.&lt;br&gt;&lt;span&gt;We built the contractor.&lt;/span&gt;&lt;/h3&gt;
    
    &lt;div&gt;
      &lt;div&gt;
        &lt;p&gt;&#129466;&lt;/p&gt;
        &lt;p&gt;CODING AGENT&lt;/p&gt;
        &lt;p&gt;Types the code you tell it to.&lt;br&gt;One file at a time.&lt;/p&gt;
      &lt;/div&gt;
      &lt;div&gt;
        &lt;p&gt;&#129504;&lt;/p&gt;
        &lt;p&gt;CONTRACTOR · REMY&lt;/p&gt;
        &lt;p&gt;Runs the entire build.&lt;br&gt;UI, API, database, deploy.&lt;/p&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Dwarf Star stores the expert weight tensors on disk. The non-expert components of the model — the attention layers, layer normalization, routing weights — stay in RAM because they’re used for every token and need to be fast. But the expert weights, which represent a large fraction of total parameters, get offloaded to disk.&lt;/p&gt;
&lt;p&gt;When inference runs and the router selects experts for a given layer, the system fetches those expert weights from the SSD, runs the computation, and moves on. The weights don’t need to stay loaded — they’ll only be needed again if that expert is selected for a future token.&lt;/p&gt;
&lt;h3 id="the-math-behind-it"&gt;The Math Behind It&lt;/h3&gt;
&lt;p&gt;Take Mixtral 8x7B as an example. Total weights are roughly 90GB in full precision, around 26GB at 4-bit quantization. A large chunk of that is expert weights.&lt;/p&gt;
&lt;p&gt;If you store experts on disk and only pull the active two per layer per token, your RAM requirement drops dramatically. The non-expert weights — the part that actually needs to stay in memory — can fit comfortably on a machine with 16–24GB of RAM.&lt;/p&gt;
&lt;p&gt;You’re not running a smaller model. You’re running the same model, with the same output quality, but with a much smaller RAM footprint.&lt;/p&gt;
&lt;h3 id="prefetching-matters"&gt;Prefetching Matters&lt;/h3&gt;
&lt;p&gt;A naive implementation would have noticeable latency: pick an expert, wait for the disk read, compute, repeat. That would be slow enough to make the approach impractical.&lt;/p&gt;
&lt;p&gt;Better implementations use prefetching. Because the routing decision for layer N is known before layer N+1 executes, the system can start loading the next layer’s experts from disk while the current computation runs. With a fast NVMe SSD (which can sustain 5–7+ GB/s sequential reads), and with careful prefetching logic, the disk reads can largely happen in parallel with compute.&lt;/p&gt;
&lt;p&gt;The result is that SSD streaming doesn’t feel like constant disk thrashing — it feels like slightly slower inference than native RAM, not like reading from a hard drive.&lt;/p&gt;
&lt;hr&gt;&lt;/section&gt;&lt;section&gt;&lt;h2 id="s-5"&gt;SSD Speed Is Not Optional&lt;/h2&gt;
&lt;p&gt;This only works if your storage is fast. A traditional SATA SSD tops out around 550 MB/s sequential read. A modern NVMe SSD using PCIe 4.0 hits 5,000–7,000 MB/s. That’s a 10x difference, and it’s the difference between a streaming approach that’s workable and one that makes inference painfully slow.&lt;/p&gt;
&lt;p&gt;If you’re considering running Dwarf Star or similar expert-streaming setups, your storage tier matters as much as your RAM:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;&lt;strong&gt;NVMe PCIe 4.0 or 5.0&lt;/strong&gt;: This is where streaming inference becomes genuinely usable. Read speeds are fast enough that prefetching keeps the pipeline fed.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;NVMe PCIe 3.0&lt;/strong&gt;: Still viable, but you’ll notice the latency more. Tokens per second will be lower.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SATA SSD&lt;/strong&gt;: Too slow for comfortable inference on most MoE models. You’ll likely bottleneck here before you bottleneck on compute.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;HDD&lt;/strong&gt;: Not a realistic option. Seek times alone make this unworkable.&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;This is worth flagging because “runs on your laptop” can mean very different things. A machine with a fast NVMe drive and 16GB RAM can have a genuinely good experience. The same RAM with a slower drive won’t.&lt;/p&gt;
&lt;hr&gt;&lt;/section&gt;&lt;section&gt;&lt;h2 id="s-6"&gt;The Trade-off Triangle: RAM, Speed, and Model Quality&lt;/h2&gt;
&lt;p&gt;SSD streaming doesn’t give you something for free. It trades one resource (RAM) for another (SSD bandwidth and some latency). Here’s how the trade-offs stack up:&lt;/p&gt;
&lt;h3 id="what-you-gain"&gt;What You Gain&lt;/h3&gt;
&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Dramatically lower RAM requirement&lt;/strong&gt;: Models that would need 40–90GB of RAM can run on 16–24GB.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Access to genuinely capable models&lt;/strong&gt;: You’re not compromising down to a smaller model — you’re running the full thing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No quality degradation&lt;/strong&gt;: The output is identical to running with full RAM. The model doesn’t know its weights are coming from disk.&lt;/li&gt;
&lt;/ul&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;
    &lt;h2&gt;
      &lt;span&gt;Other agents ship a demo.&lt;/span&gt;
      &lt;span&gt;Remy ships an app.&lt;/span&gt;
    &lt;/h2&gt;
    &lt;div&gt;
      &lt;div&gt;
        &lt;p&gt;&lt;span&gt;UI&lt;/span&gt;&lt;/p&gt;
        &lt;span&gt;React + Tailwind&lt;/span&gt;
        &lt;span&gt;✓ LIVE&lt;/span&gt;
      &lt;/div&gt;
      &lt;div&gt;
        &lt;p&gt;&lt;span&gt;API&lt;/span&gt;&lt;/p&gt;
        &lt;span&gt;REST · typed contracts&lt;/span&gt;
        &lt;span&gt;✓ LIVE&lt;/span&gt;
      &lt;/div&gt;
      &lt;div&gt;
        &lt;p&gt;&lt;span&gt;DATABASE&lt;/span&gt;&lt;/p&gt;
        &lt;span&gt;real SQL, not mocked&lt;/span&gt;
        &lt;span&gt;✓ LIVE&lt;/span&gt;
      &lt;/div&gt;
      &lt;div&gt;
        &lt;p&gt;&lt;span&gt;AUTH&lt;/span&gt;&lt;/p&gt;
        &lt;span&gt;roles · sessions · tokens&lt;/span&gt;
        &lt;span&gt;✓ LIVE&lt;/span&gt;
      &lt;/div&gt;
      &lt;div&gt;
        &lt;p&gt;&lt;span&gt;DEPLOY&lt;/span&gt;&lt;/p&gt;
        &lt;span&gt;git-backed, live URL&lt;/span&gt;
        &lt;span&gt;✓ LIVE&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;p&gt;Real backend. Real database. Real auth. Real plumbing. Remy has it all.&lt;/p&gt;
  &lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h3 id="what-you-give-up"&gt;What You Give Up&lt;/h3&gt;
&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Tokens per second&lt;/strong&gt;: Inference is slower than native RAM loading. How much slower depends on your SSD speed, the model, and how effective the prefetching is. Expect noticeably fewer tokens per second than a fully RAM-loaded run.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SSD write endurance (minor)&lt;/strong&gt;: Heavy inference use means lots of reads. SSDs have endurance ratings. For most users, this isn’t a practical concern — but it’s worth knowing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Latency on first token&lt;/strong&gt;: The initial load can take a moment as the first experts get pulled from disk.&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;For interactive use — asking questions, generating code, writing — the speed trade-off is usually acceptable. For batch inference or applications that need to process thousands of requests, you’d want native RAM or cloud infrastructure instead.&lt;/p&gt;
&lt;hr&gt;&lt;/section&gt;&lt;section&gt;&lt;h2 id="s-7"&gt;Who This Is Actually For&lt;/h2&gt;
&lt;p&gt;SSD streaming is a specific solution for a specific problem. It’s worth being honest about the audience.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It’s a good fit if:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;You want to run a high-capability MoE model locally and have 16–24GB RAM&lt;/li&gt;
&lt;li&gt;You have a fast NVMe SSD with adequate free space&lt;/li&gt;
&lt;li&gt;Your use case is interactive or low-throughput (personal use, development, research)&lt;/li&gt;
&lt;li&gt;You care about privacy or offline access and can’t or don’t want to use cloud APIs&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;It’s probably not the right fit if:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;You need high-throughput inference (many requests per minute)&lt;/li&gt;
&lt;li&gt;Your SSD is slow (SATA or older NVMe)&lt;/li&gt;
&lt;li&gt;You’re building a production system that serves multiple users&lt;/li&gt;
&lt;li&gt;The latency trade-off would visibly degrade your end-user experience&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;It’s also worth noting that SSD streaming is most relevant for MoE architectures. Dense models don’t have the same natural partition — there’s no concept of “active vs. inactive” weights at inference time in the same way. Applying streaming to a dense model would require different approaches and would likely be significantly less efficient.&lt;/p&gt;
&lt;hr&gt;&lt;/section&gt;&lt;section&gt;&lt;h2 id="s-8"&gt;Where Cloud Models Change the Calculation&lt;/h2&gt;
&lt;p&gt;For most people building AI-powered applications, the local hardware constraint is the wrong problem to be solving. Running a model locally makes sense for privacy-critical applications, offline use, or research. But if you’re building something that needs to work reliably, serve multiple users, or access the best available models, cloud inference is the practical path.&lt;/p&gt;
&lt;p&gt;This is where something like &lt;a href="https://mindstudio.ai"&gt;MindStudio&lt;/a&gt; fits into the picture. MindStudio gives you access to 200+ models — Claude, GPT-4o, Gemini, Mistral, and others — without managing API keys, worrying about RAM constraints, or thinking about SSD speeds. You pick the model that fits your task, and the infrastructure is already handled.&lt;/p&gt;
&lt;p&gt;For teams building AI agents and automated workflows, that matters more than most people realize. The bottleneck isn’t usually “can I run this model” — it’s “can I connect this model to the right data, trigger it at the right time, and get the output into the right system.” MindStudio’s visual workflow builder handles exactly that: connecting models to business tools, building multi-step pipelines, and deploying without writing infrastructure code.&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;div&gt;
    &lt;p&gt;
      &lt;/p&gt;&lt;h2&gt;
        &lt;span&gt;Other agents start typing.&lt;/span&gt;
        &lt;span&gt;Remy starts asking.&lt;/span&gt;
      &lt;/h2&gt;
    
    &lt;p&gt;
      &lt;span&gt;YOU SAID&lt;/span&gt;
      &lt;span&gt;"Build me a sales CRM."&lt;/span&gt;
    &lt;/p&gt;
    &lt;p&gt;REMY ASKS&lt;/p&gt;
    &lt;div&gt;
      &lt;p&gt;
        &lt;span&gt;01&lt;/span&gt;
        &lt;span&gt;DESIGN&lt;/span&gt;
        &lt;span&gt;Should it feel like Linear, or Salesforce?&lt;/span&gt;
      &lt;/p&gt;
      &lt;p&gt;
        &lt;span&gt;02&lt;/span&gt;
        &lt;span&gt;UX&lt;/span&gt;
        &lt;span&gt;How do reps move deals — drag, or dropdown?&lt;/span&gt;
      &lt;/p&gt;
      &lt;p&gt;
        &lt;span&gt;03&lt;/span&gt;
        &lt;span&gt;ARCH&lt;/span&gt;
        &lt;span&gt;Single team, or multi-org with permissions?&lt;/span&gt;
      &lt;/p&gt;
    &lt;/div&gt;
    &lt;p&gt;Scoping, trade-offs, edge cases — the real work. Before a line of code.&lt;/p&gt;
  &lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If you’re interested in what capable models can actually do in production rather than in your terminal, &lt;a href="https://mindstudio.ai"&gt;you can try MindStudio free at mindstudio.ai&lt;/a&gt;. It’s a different solution to the same underlying goal: getting access to capable AI without the friction.&lt;/p&gt;
&lt;hr&gt;&lt;/section&gt;&lt;section&gt;&lt;h2 id="s-9"&gt;Practical Setup Considerations for SSD Streaming&lt;/h2&gt;
&lt;p&gt;If you’re interested in trying expert streaming locally, here’s what to think through before starting.&lt;/p&gt;
&lt;h3 id="storage-requirements"&gt;Storage Requirements&lt;/h3&gt;
&lt;p&gt;Large MoE models are large. Mixtral 8x7B at 4-bit quantization is around 26GB. Larger models like Mixtral 8x22B run over 80GB even quantized. Make sure you have adequate free space — running out mid-inference is painful.&lt;/p&gt;
&lt;h3 id="quantization-still-helps"&gt;Quantization Still Helps&lt;/h3&gt;
&lt;p&gt;SSD streaming and quantization work together. A 4-bit or 8-bit quantized model still produces the expert streaming benefit, and smaller file sizes mean faster disk reads. GGUF format (used by llama.cpp) and similar quantized formats are generally compatible with streaming approaches.&lt;/p&gt;
&lt;h3 id="ram-allocation"&gt;RAM Allocation&lt;/h3&gt;
&lt;p&gt;You’ll want to be deliberate about what stays in RAM versus what streams from disk. The routing logic, attention layers, and other non-expert components should stay in RAM for speed. Most expert streaming implementations handle this automatically, but knowing the split helps you debug if something’s slow.&lt;/p&gt;
&lt;h3 id="thermal-throttling-on-laptops"&gt;Thermal Throttling on Laptops&lt;/h3&gt;
&lt;p&gt;Sustained inference on a laptop will push both CPU and SSD hard. SSDs throttle when they get hot, which will slow your reads and hurt inference speed. If you’re doing long inference sessions on a laptop, this is worth monitoring.&lt;/p&gt;
&lt;hr&gt;&lt;/section&gt;&lt;section&gt;&lt;h2 id="s-10"&gt;Frequently Asked Questions&lt;/h2&gt;
&lt;h3 id="what-is-ssd-streaming-for-ai-models"&gt;What is SSD streaming for AI models?&lt;/h3&gt;
&lt;p&gt;SSD streaming is a technique that stores model weights on an SSD rather than keeping them entirely in RAM. During inference, the system loads only the weights it currently needs from disk, runs the computation, and discards or cycles them. This reduces RAM requirements significantly while maintaining full model quality, at the cost of some inference speed.&lt;/p&gt;
&lt;h3 id="does-ssd-streaming-reduce-model-quality"&gt;Does SSD streaming reduce model quality?&lt;/h3&gt;
&lt;p&gt;No. The model weights are identical — they’re just stored on disk rather than RAM. The outputs of inference are the same as if you’d loaded everything into RAM. Quality is only affected if you also apply additional quantization on top of the streaming setup, which is separate.&lt;/p&gt;
&lt;h3 id="what-kind-of-ssd-do-i-need-for-ai-model-streaming"&gt;What kind of SSD do I need for AI model streaming?&lt;/h3&gt;
&lt;p&gt;You need an NVMe SSD, ideally PCIe 4.0 or better. These drives achieve sequential read speeds of 5,000–7,000 MB/s, which is fast enough for prefetching to work effectively. SATA SSDs (capped around 550 MB/s) are generally too slow for comfortable inference. PCIe 3.0 NVMe drives are workable but will show more latency.&lt;/p&gt;
&lt;h3 id="why-does-ssd-streaming-work-better-for-moe-models"&gt;Why does SSD streaming work better for MoE models?&lt;/h3&gt;
&lt;p&gt;Mixture of Experts models only activate a fraction of their expert networks per token — typically two out of eight or more. This creates a natural partition between “weights needed right now” and “weights that can stay on disk.” Dense models don’t have this partition, so streaming them is less efficient — you’d need all weights for every forward pass.&lt;/p&gt;
&lt;h3 id="how-does-dwarf-star-differ-from-just-using-swap-space"&gt;How does Dwarf Star differ from just using swap space?&lt;/h3&gt;
&lt;div&gt;&lt;div&gt;&lt;div&gt;
    &lt;p&gt;REMY IS NOT&lt;/p&gt;
    &lt;ul&gt;&lt;li&gt;&lt;span&gt;✕&lt;/span&gt;&lt;span&gt;a coding agent&lt;/span&gt;&lt;/li&gt;
      &lt;li&gt;&lt;span&gt;✕&lt;/span&gt;&lt;span&gt;no-code&lt;/span&gt;&lt;/li&gt;
      &lt;li&gt;&lt;span&gt;✕&lt;/span&gt;&lt;span&gt;vibe coding&lt;/span&gt;&lt;/li&gt;
      &lt;li&gt;&lt;span&gt;✕&lt;/span&gt;&lt;span&gt;a faster Cursor&lt;/span&gt;&lt;/li&gt;
    &lt;/ul&gt;&lt;p&gt;IT IS&lt;/p&gt;
    &lt;p&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt;a general contractor for software&lt;/span&gt;&lt;/p&gt;
    &lt;p&gt;The one that tells the coding agents what to build.&lt;/p&gt;
  &lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Operating system swap space uses disk as a passive overflow when RAM fills up. It’s not optimized for sequential weight loading and lacks any awareness of model structure or inference patterns. Dwarf Star actively manages which weights to load, when to load them, and uses prefetching based on routing decisions to hide disk latency. It’s a purpose-built system, not a generic fallback.&lt;/p&gt;
&lt;h3 id="can-i-use-ssd-streaming-for-production-applications"&gt;Can I use SSD streaming for production applications?&lt;/h3&gt;
&lt;p&gt;For low-traffic or single-user scenarios, it’s viable. For production systems handling multiple concurrent users or requiring high throughput, the latency and bandwidth limitations of SSD streaming become problematic. In those cases, cloud inference or dedicated GPU infrastructure is more appropriate.&lt;/p&gt;
&lt;hr&gt;&lt;/section&gt;&lt;section&gt;&lt;h2 id="s-11"&gt;Key Takeaways&lt;/h2&gt;
&lt;ul&gt;&lt;li&gt;RAM has historically been a binary constraint for local AI models — either the full model fits or it doesn’t run. SSD streaming turns it into a sliding scale.&lt;/li&gt;
&lt;li&gt;MoE architectures make SSD streaming practical because only a subset of expert weights are active at any given time — the rest can live on disk without affecting output quality.&lt;/li&gt;
&lt;li&gt;Dwarf Star implements this by streaming expert weights from SSD to RAM on demand, with prefetching to minimize latency impact.&lt;/li&gt;
&lt;li&gt;NVMe SSD speed is critical. PCIe 4.0 drives make this approach genuinely usable; slower storage undermines the value.&lt;/li&gt;
&lt;li&gt;The trade-off is tokens per second, not quality. Outputs are identical to a fully RAM-loaded run — inference is just slower.&lt;/li&gt;
&lt;li&gt;For most people building AI-powered applications, cloud inference through a platform like &lt;a href="https://mindstudio.ai"&gt;MindStudio&lt;/a&gt; eliminates the hardware constraint entirely and lets you focus on what the models actually do rather than how to make them run.&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/body&gt;&lt;/html&gt;</content>
        <author>
            <name/>
        </author>
        <media:content medium="image" url="https://i.mscdn.ai/70cbb1ad-08d7-4fdc-ab31-e343780966a6/generated-images/64da3721-843c-4efa-a497-30af3cdf3b65.png?fm=auto&amp;w=1200&amp;h=630&amp;fit=crop"/>
        <source>
            <id>tag:feedly.com,2013:cloud/feed/https://www.mindstudio.ai/rss.xml</id>
            <title type="html">MindStudio</title>
            <link href="https://www.mindstudio.ai" rel="alternate" type="text/html"/>
            <updated>2026-08-07T10:58:48Z</updated>
        </source>
    </entry>
    <entry>
        <id>tag:feedly.com,2013:cloud/entry/cOXRjoksGIQzU1pdqbdybn+OTWYeI0riptNneGckdsI=_19f714b9083:193b35:54ced93c</id>
        <title type="html">New research: The Core Web Vitals thresholds you trust might be wrong for your site</title>
        <published>2026-07-17T18:16:45Z</published>
        <updated>2026-07-17T18:16:49Z</updated>
        <link href="https://embrace.io/blog/research-core-web-vitals/" rel="alternate" type="text/html"/>
        <summary type="html">Core Web Vitals data from ten leading online retailers reveals that &amp;quot;good&amp;quot; for Google may not be good enough for your users or your business.</summary>
        <content type="html">&lt;!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"&gt;
&lt;html&gt;&lt;body&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;
		&lt;div&gt;
			&lt;p&gt;I decided to dig into my questions properly. I pulled a month of real user data from ten leading online retailers and built a correlation chart for each one, plotting session-level Largest Contentful Paint (LCP) data against bounce rate for each site.&lt;/p&gt;
&lt;p&gt;Before we get into the findings, first I want to cover what a performance correlation chart is and what it shows you.&lt;/p&gt;
&lt;p&gt;A correlation chart is a powerful data visualization that shows you the relationship between your page speed metrics and your business and user engagement metrics.&lt;/p&gt;
&lt;p&gt;To illustrate, here’s the correlation chart for the first retail site in this research:&lt;/p&gt;

		&lt;/div&gt;
	&lt;/div&gt;
&lt;div&gt;
		&lt;div&gt;
			&lt;p&gt;Correlation charts are generated using real user monitoring (RUM) data. They give you a histogram view of all your user traffic, broken out into cohorts based on performance metrics, such as Start Render, Largest Contentful Paint, Interaction to Next Paint, and more. Each cohort shows you the median time for whatever metric you’re tracking for the session. (Those cohorts are represented in the yellow columns in the chart above.)&lt;/p&gt;
&lt;p&gt;The next layer of the chart is where things get really interesting.&lt;/p&gt;
&lt;p&gt;You also get an overlay (the blue line in the chart above) that shows you the business or user engagement metric – commonly conversion rate or bounce rate, but there are many more – that correlates to each of these cohorts. This lets you see at a glance how closely your business/engagement metric aligns with the speed of your site.&lt;/p&gt;
&lt;p&gt;For this investigation, I focused on bounce rate rather than conversion rate because it’s captured by default in most RUM tools, so there’s no extra instrumentation required. It’s also a good directional proxy. In my experience, if you see a relationship between a performance metric and bounce rate, there’s a good chance a similar relationship exists with conversion rate, too.&lt;/p&gt;
&lt;p&gt;On the correlation chart for each site, I marked three points:&lt;/p&gt;

		&lt;/div&gt;
	&lt;/div&gt;
&lt;div&gt;
		&lt;div&gt;
			&lt;p&gt;If you’re not familiar with the performance plateau, &lt;a href="https://www.speedcurve.com/blog/web-performance-plateau/" target="_blank"&gt;I’ve written about it before&lt;/a&gt;. Short version: every site eventually hits a point where shaving off more milliseconds stops moving the needle on engagement. Below that point, speed matters a lot. Beyond it, you’re optimizing for nothing.&lt;/p&gt;

		&lt;/div&gt;
	&lt;/div&gt;
&lt;div&gt;
		&lt;div&gt;
			&lt;p&gt;Across all ten retailers, the optimal LCP — the point tied to the best bounce rate — ranged from &lt;strong&gt;100 milliseconds to 1 second&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Not 2.5 seconds.&lt;/p&gt;
&lt;p&gt;Every one of these sites saw its best engagement well before Google’s “good” threshold. For several sites, 2.5 seconds was already sitting on the plateau – the zone where speed had stopped helping long before.&lt;/p&gt;

		&lt;/div&gt;
	&lt;/div&gt;
&lt;div&gt;
		&lt;div&gt;
			&lt;p&gt;&lt;strong&gt;I want to emphasize this before I go on: this is NOT a new number for you to chase.&lt;/strong&gt; 100ms–1s isn’t a universal target any more than 2.5 seconds is. That’s exactly the trap we’re trying to avoid. What it tells you is that “good enough” – for real users on real sites – can be much faster than the industry standard suggests. The only way to know your number is to look at your own data.&lt;/p&gt;

		&lt;/div&gt;
	&lt;/div&gt;
&lt;div&gt;
		&lt;div&gt;
			&lt;p&gt;The start time for the performance plateau ranged from 500 milliseconds to 5.6 seconds across all ten sites. This wasn’t surprising. There’s typically a lot of variance in how the performance plateau manifests across different sites.&lt;/p&gt;
&lt;p&gt;What was surprising was that, for four of the ten sites, the performance plateau started &lt;em&gt;before&lt;/em&gt; 2.5 seconds. By the time those four sites met Google’s recommended threshold for “good” Largest Contentful Paint time, they were already on the performance plateau.&lt;/p&gt;
&lt;p&gt;In other words, &lt;strong&gt;even though these four sites are technically fast enough for Google, they’ve actually bottomed out in terms of bounce rate&lt;/strong&gt;.&lt;/p&gt;

		&lt;/div&gt;
	&lt;/div&gt;
&lt;div&gt;
		&lt;div&gt;
			&lt;p&gt;At the risk of repeating myself (but it bears repeating), you should never assume that meeting external thresholds is actually helping your business. You need to look at your own data to set meaningful targets.&lt;/p&gt;

		&lt;/div&gt;
	&lt;/div&gt;
&lt;div&gt;
		&lt;div&gt;
			&lt;p&gt;Below, I’m sharing the correlation chart for each of the ten retailers, along with what stood out in each one: where the optimal LCP landed, where the plateau began, and anything else worth noting about the shape of the curve.&lt;/p&gt;
&lt;p&gt;To be completely candid, even though I hypothesized these results, I was surprised at how consistent they were.&lt;/p&gt;

		&lt;/div&gt;
	&lt;/div&gt;
&lt;div&gt;
		&lt;div&gt;
			&lt;p&gt;It’s tempting to look at “100 milliseconds to 1 second” and treat it as a new target to chase. Please, please don’t. As I mentioned earlier, that’s exactly the trap we’re trying to avoid. Consider this research a methodology, not a number.&lt;/p&gt;
&lt;p&gt;The good news is that the method is straightforward:&lt;/p&gt;
&lt;ol&gt;&lt;li&gt;Pull your own RUM data.&lt;/li&gt;
&lt;li&gt;Build a correlation chart plotting LCP (or any other user-oriented metric) against bounce rate.&lt;/li&gt;
&lt;li&gt;Find where your bounce rate is actually at its best, and where your plateau begins.&lt;/li&gt;
&lt;li&gt;Set your performance goals based on that – not on a number based on millions of sites you don’t run.&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;Your optimal LCP might turn out to be 1.8 seconds. It might be 400 milliseconds. It might be 5 seconds. Who knows! There’s no way to know without looking. But if these ten retailers are any indication, “fast enough” may be faster than the industry standard suggests. &lt;strong&gt;Treating 2.5 seconds as your finish line could mean leaving engagement and revenue on the table without realizing it.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you run this analysis on your own site, I’d love to hear what you find! If you’re an Embrace/SpeedCurve customer and you want to know how to do your own investigation, let me know and I’ll be happy to help.&lt;/p&gt;

		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/body&gt;&lt;/html&gt;</content>
        <author>
            <name>Tammy Everts</name>
        </author>
        <media:content medium="image" url="https://embrace.io/wp-content/uploads/2026/07/LCP-retail-research-hero-NEW2.gif"/>
        <source>
            <id>tag:feedly.com,2013:cloud/feed/https://embrace.io/feed/</id>
            <title type="html">Embrace</title>
            <link href="https://embrace.io" rel="alternate" type="text/html"/>
            <updated>2026-07-17T18:16:49Z</updated>
        </source>
    </entry>
    <entry>
        <id>tag:feedly.com,2013:cloud/entry/cOXRjoksGIQzU1pdqbdybn+OTWYeI0riptNneGckdsI=_19f215420f5:1bc635:3cf045dc</id>
        <title type="html">A Boring Tiny Tooling paradigm</title>
        <published>2026-07-02T05:36:29Z</published>
        <updated>2026-07-02T05:36:33Z</updated>
        <link href="https://vaughntan.org/bttparadigm" rel="alternate" type="text/html"/>
        <summary type="html">tl;dr: Small-medium businesses are missing a huge opportunity because of three imagination failures: they believe digital transformation must be big</summary>
        <content type="html">&lt;!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"&gt;
&lt;html&gt;&lt;body&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;

        

        &lt;p&gt;
          6/1/2026

            ☼ &lt;a href="https://vaughntan.org/tagged/product"&gt;product&lt;/a&gt;
            ☼ &lt;a href="https://vaughntan.org/tagged/consulting"&gt;consulting&lt;/a&gt;
            ☼ &lt;a href="https://vaughntan.org/tagged/ai"&gt;AI&lt;/a&gt;
            ☼ &lt;a href="https://vaughntan.org/tagged/btt"&gt;BTT&lt;/a&gt;
        &lt;/p&gt;

        

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;tl;dr:&lt;/strong&gt; Small-medium businesses are missing a huge opportunity because of three imagination failures: they believe digital transformation must be big and disruptive, they haven’t recalibrated software buying for the collapse in software development costs, and they don’t realise this economic shift requires a different consulting approach. These businesses need Boring Tiny Tools (very narrowly scoped software automating repetitive workflows) built by amorphous consultants who observe actual operations before proposing solutions.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Over the last year, I’ve been writing about and doing a lot of &lt;a href="https://vaughntan.org/amorphousconsulting"&gt;amorphous consulting&lt;/a&gt; while using the &lt;a href="https://vaughntan.org/meaningmakingai"&gt;meaningmaking lens to think practically about what human work should be in a time of &lt;span&gt;AI&lt;/span&gt;&lt;/a&gt;. In doing that, I’ve spent a lot of time both in and lurking at the edges of conversations with people working at the cutting edge of &lt;span&gt;AI&lt;/span&gt; use. I recently had a long call with &lt;a href="https://roblog.co.uk/about/" target="_blank"&gt;Rob Miller&lt;/a&gt;, a software developer and independent consultant who emailed me after reading &lt;a href="https://vaughntan.org/boringtinytools"&gt;an essay I wrote about Boring Tiny Tools&lt;/a&gt;. (A &lt;span&gt;BTT&lt;/span&gt; is a &lt;em&gt;very&lt;/em&gt; narrowly scoped piece of software that automates boring, routine workflows without disrupting other workflows.)&lt;/p&gt;
&lt;p&gt;Rob told me about spending a single afternoon building a &lt;span&gt;BTT&lt;/span&gt; for his wife’s firm, a barristers’ chambers. This &lt;span&gt;BTT&lt;/span&gt; is a court submission preparation tool that works on-premises to be compliant with data protection. The tool makes &lt;span&gt;PDF&lt;/span&gt; multi-document bundles, automatically creates hyperlinked tables of contents, and formats the bundle to court specifications. Error-prone humans used to spend hours doing this boring job manually. Now it is a software-enabled, reliable automated process that takes minutes. Multiply that across 50-60 people and thousands of cases per year in the organisation and the savings quickly stack up.&lt;/p&gt;
&lt;p&gt;Rob’s &lt;span&gt;BTT&lt;/span&gt; is yet another validation of the new emerging paradigm I’m seeing (and am maybe a part of) at the place where software, consulting, and digital transformation touch each other. The greatest potential beneficiaries of this new paradigm are small-medium businesses with a particular profile:&lt;/p&gt;
&lt;ol type="1"&gt;&lt;li&gt;Small enough to have no in-house transformation tools team, &lt;strong&gt;but&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Large enough that efficiency gains from transformation save a significant amount of money annually (say, millions vs tens of thousands of dollars), &lt;strong&gt;but&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Not so large that transformation savings justify spending hundreds of thousands of dollars on conventional transformation consultants to write bespoke business process software.&lt;/li&gt;
&lt;/ol&gt;&lt;h2 id="three-imagination-failures"&gt;Three imagination failures&lt;/h2&gt;
&lt;p&gt;Unfortunately, these small-medium businesses don’t actually seem to be benefiting yet. It’s more accurate to say that the new &lt;strong&gt;Boring Tiny Tooling Paradigm&lt;/strong&gt; is struggling to emerge but three related imagination failures keep getting in the way.&lt;/p&gt;
&lt;p&gt;These three imagination failures affect the idea of what transformation should look like, what the software that enables it should be, and what kind of consulting approach to buy:&lt;/p&gt;
&lt;ol type="1"&gt;&lt;li&gt;&lt;strong&gt;Inability to conceive of digital transformation as anything other than Grand and Disruptive.&lt;/strong&gt; Only big strategic software deployments, enterprise platforms, major integrations, or organisation-wide rollouts are legible as transformation. BTTs that address a profusion of tiny business processes don’t read as transformation, even when the return on investment is both immediate and measurable.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Inability to recalibrate the scale of software bought to account for the sudden collapse in the cost of writing software.&lt;/strong&gt; Software that used to cost tens of thousands of dollars and take months to write now costs thousands of dollars and takes days to write. It’s finally economically feasible to write BTTs to automate tiny, boring business processes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Inability to see that the collapse in software economics necessitates a different transformation consulting approach.&lt;/strong&gt; That BTTs are suddenly cheap, fast, and viable to build should be feeding through to the kinds of transformation consulting services businesses buy … but businesses continue to want conventional consulting services that price and deploy oversize, too-expensive transformation solutions based on pre-collapse software economics.&lt;/li&gt;
&lt;/ol&gt;&lt;h2 id="a-consulting-problem"&gt;A consulting problem&lt;/h2&gt;
&lt;p&gt;That last imagination failure is the big one.&lt;/p&gt;
&lt;p&gt;When businesses can only imagine transformations that are big and legible, they look for and engage conventional consultants who promise big legible transformations. These conventional consultants scope and deliver expensive and needlessly enterprise-scale solutions to justify their big fees and promises of big transformations.&lt;/p&gt;
&lt;p&gt;(It is now an open secret that the big consulting firms are using &lt;span&gt;AI&lt;/span&gt; tools internally to cut development time while still charging out at pre-AI prices. They keep the difference and have no incentive to educate clients about these new economics.)&lt;/p&gt;
&lt;p&gt;Meanwhile, what the small-medium business actually needs is a different consulting approach entirely: What I call &lt;a href="https://vaughntan.org/amorphousconsulting"&gt;amorphous consulting&lt;/a&gt;. In contrast to conventional consulting, amorphous consulting comes into a client engagement with an open mind about the problem and the solution.&lt;/p&gt;
&lt;p&gt;Rob’s bundle preparation tool was a solution scoped out of a deep understanding of the user’s real operational problems. The amorphous consultant gets this kind of deep understanding by spending time observing what’s happening in the client’s organisation. This approach to consulting leads to tiny, boring, highly effective solutions. When software is scoped and built by amorphous consultants, it is more likely to be&lt;/p&gt;
&lt;ol type="1"&gt;&lt;li&gt;Minimal and fast to build (because the scope will be limited to only features needed to address the actual problem to be solved),&lt;/li&gt;
&lt;li&gt;Functional within actual operational constraints faced by users on the ground,&lt;/li&gt;
&lt;li&gt;Actually adopted by users with operational responsibilities, and&lt;/li&gt;
&lt;li&gt;Undisruptive to other workflows.&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;These are all desirable characteristics of transformation software.&lt;/p&gt;
&lt;p&gt;How Rob scoped and built his &lt;span&gt;BTT&lt;/span&gt; — prompted by a serendipitous observation of his wife doing silly rote work to prepare a bundle manually while on holiday in Champagne — is an example of the kind of amorphous consulting approach that most small-medium businesses actually need.&lt;/p&gt;
&lt;p&gt;Unfortunately, most of these businesses don’t know how to procure these kinds of amorphous consulting services where the scopes of work and target deliverables can’t (and shouldn’t be) defined in advance.&lt;/p&gt;
&lt;h2 id="imagination-is-the-hard-part"&gt;Imagination is the hard part&lt;/h2&gt;
&lt;p&gt;As I wrote in &lt;a href="https://uncertaintymindset.substack.com/p/ai-missing-middle" target="_blank"&gt;&lt;span&gt;AI&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;’&lt;/span&gt;s missing middle&lt;/a&gt;, small-medium firms in traditional industries represent a massive market and a massive missed opportunity. (Policymakers and investors might want to take note.) Small-medium firms don’t need fancy conventional consultants and their overscoped and expensively disruptive software. What they do need are Boring Tiny Tools scoped and built by amorphous consultants.&lt;/p&gt;
&lt;p&gt;None of this is expensive or technically challenging. All it takes is better imagination.&lt;/p&gt;

        
    
      

&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/body&gt;&lt;/html&gt;</content>
        <author>
            <name/>
        </author>
        <source>
            <id>tag:feedly.com,2013:cloud/feed/https://vaughntan.org/feed.rss</id>
            <title type="html">vaughntan.org</title>
            <link href="https://vaughntan.org" rel="alternate" type="text/html"/>
            <updated>2026-07-02T05:36:33Z</updated>
        </source>
    </entry>
    <entry>
        <id>tag:feedly.com,2013:cloud/entry/cOXRjoksGIQzU1pdqbdybn+OTWYeI0riptNneGckdsI=_19f16a13cf3:1fc5de:4f181844</id>
        <title type="html">Even with a silver bullet, you still have to aim</title>
        <published>2026-06-30T03:44:53Z</published>
        <updated>2026-06-30T03:44:56Z</updated>
        <link href="https://productpicnic.beehiiv.com/p/even-with-a-silver-bullet-you-still-have-to-aim" rel="alternate" type="text/html"/>
        <summary type="html">Productivity gains among frontline employees can't counteract the abdication of responsibility at the executive level.</summary>
        <content type="html">&lt;!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"&gt;
&lt;html&gt;&lt;body&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;As George Lucas once said, for some reason: history is like poetry. It rhymes.&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;Our industry is certainly rhyming with a historical era I love to pick on: the boom in tech investment that followed the one-two punch of the Dot Com Bust and the Financial Crisis. Companies and their investors were desperate to find that one silver bullet that would turn everything around. Back then, that silver bullet was Design Thinking. Big tech poached designers from celebrated consultancies and airdropped them into pure chaos without a plan beyond “fix the product for us.”&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;Ten years after design thinking’s heyday, there’s a new silver bullet that everyone has pinned their hopes on, without a clear idea of what exactly it will do. At this point in the hype cycle, you’ve seen the numbers for yourselves: billions in investments, and loud cricket noises for returns. Anecdotes of individual productivity gains are easy to come by, and yet they do not translate to improvements in the bottom line!&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;What’s actually making teams move faster is &lt;/span&gt;&lt;span&gt;&lt;a href="https://www.linkedin.com/posts/mbowler_self-sufficient-teams-activity-7470482224623157250-XNt-/?utm_campaign=even-with-a-silver-bullet-you-still-have-to-aim&amp;amp;utm_medium=referral&amp;amp;utm_source=productpicnic.beehiiv.com" target="_blank" rel=""&gt;org design&lt;/a&gt;&lt;/span&gt;&lt;span&gt;. Taking care of organizational dysfunction may be a side effect of “AI transformation” but it sure seems to be offering the majority of the benefits.&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;p&gt;❝&lt;/p&gt;&lt;div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;Consider &lt;/span&gt;&lt;span&gt;&lt;a href="https://blog.mikebowler.ca/2024/07/02/self-sufficient-teams/?utm_campaign=even-with-a-silver-bullet-you-still-have-to-aim&amp;amp;utm_medium=referral&amp;amp;utm_source=productpicnic.beehiiv.com" target="_blank" rel=""&gt;this story&lt;/a&gt;&lt;/span&gt;&lt;span&gt; when the right handpicked people completed in 3 hours, a piece of work estimated at 10-12 weeks. That story was from roughly ten years ago, well before any of the AI tools appeared on the scene. It didn’t rely on magical tooling, it just needed us to &lt;/span&gt;&lt;span&gt;&lt;strong&gt;undo some organizational dysfunction and to put the right people in the room&lt;/strong&gt;&lt;/span&gt;&lt;span&gt; to collaborate on the problem. &lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p id="the-purpose-of-a-system-is-what-it-"&gt;&lt;/p&gt;&lt;h1&gt;&lt;span&gt;The purpose of a system is what it does&lt;/span&gt;&lt;/h1&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;“AI works” vs “AI doesn’t work” is an exhausting debate; no one is ever convinced of anything and the only winners of the arguments are keyboard manufacturers. I’m not going to go over the various hallucination rates and studies on how much longer it takes to check an AI’s output for errors than to just do it yourself. Even with 0% error rates, those figures would be besides the point. The biggest problem — and don’t take my word for it, listen to some Nobel laureate guy — is that &lt;/span&gt;&lt;span&gt;&lt;a href="https://finance.yahoo.com/technology/ai/articles/nobel-laureate-daron-acemoglu-brainless-090000758.html?utm_campaign=even-with-a-silver-bullet-you-still-have-to-aim&amp;amp;utm_medium=referral&amp;amp;utm_source=productpicnic.beehiiv.com" target="_blank" rel=""&gt;the bottleneck lies upstream of your Jira ticket&lt;/a&gt;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;p&gt;❝&lt;/p&gt;&lt;div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;Most research on AI productivity is overblown because it overwhelmingly focuses on easy, well-defined tasks where context is clear. These are not representative of the economy, which simply isn't set up with so many of those.&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;We are not in the future. It is still 2016. It is still &lt;/span&gt;&lt;span&gt;&lt;em&gt;1986&lt;/em&gt;&lt;/span&gt;&lt;span&gt;, if you are so inclined. We have hardly made any strides in our ability to define tasks and their context. What baby steps we’ve made in the right direction have been swallowed up by a great cloud of noise. For every Toyota Way book written in the 90s, there is a &lt;/span&gt;&lt;span&gt;&lt;a href="https://www.the-independent.com/tech/ford-ai-automation-human-workers-b3003787.html?utm_campaign=even-with-a-silver-bullet-you-still-have-to-aim&amp;amp;utm_medium=referral&amp;amp;utm_source=productpicnic.beehiiv.com" target="_blank" rel=""&gt;Ford counterexample&lt;/a&gt;&lt;/span&gt;&lt;span&gt; being eagerly practiced today.&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;AI has intensified this problem, as it intensifies all things to which it is applied. But the problem did not originate with AI. Before Claude could learn to talk like the median LinkedIn influencer, the median LinkedIn influencer had to &lt;/span&gt;&lt;span&gt;&lt;a href="https://www.linkedin.com/posts/cameron-tonkinwise-80a5987_zuckerberg-urges-meta-to-explore-working-activity-7476445339470823424-Ug96/?utm_campaign=even-with-a-silver-bullet-you-still-have-to-aim&amp;amp;utm_medium=referral&amp;amp;utm_source=productpicnic.beehiiv.com" target="_blank" rel=""&gt;arrive at that mindset&lt;/a&gt;&lt;/span&gt;&lt;span&gt; under their own power:&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;p&gt;❝&lt;/p&gt;&lt;div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;Criticism of the […] slop genAI produces invariably fails to acknowledge how much &lt;/span&gt;&lt;span&gt;&lt;strong&gt;slop-ification was already characterising so many discourses prior to retail LLMs&lt;/strong&gt;&lt;/span&gt;&lt;span&gt;: PEEL paragraphs, Powerpoint slides, TED talks, Big Consultancy strategy canvases, PR company produced apologies to customers, LinkedIn posts...&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p id="the-bottleneck-is-the-context-in-wh"&gt;&lt;/p&gt;&lt;h1&gt;&lt;span&gt;The bottleneck is the context in which the work takes place&lt;/span&gt;&lt;/h1&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;For every step a would-be thought leader took towards “synergistic leadership” or “growth-hacking paradigms” they took a step &lt;/span&gt;&lt;span&gt;&lt;a href="https://news.cornell.edu/stories/2026/03/workers-who-love-synergizing-paradigms-might-be-bad-their-jobs?utm_campaign=even-with-a-silver-bullet-you-still-have-to-aim&amp;amp;utm_medium=referral&amp;amp;utm_source=productpicnic.beehiiv.com" target="_blank" rel=""&gt;away from reality&lt;/a&gt;&lt;/span&gt;&lt;span&gt;. And corporate bullshit (not my name for it but a real term of the art, take it up with Cornell!) is not the only layer lubricating a product’s slide into slop. Robert Fabricant has &lt;/span&gt;&lt;span&gt;&lt;a href="https://www.fastcompany.com/91563306/are-designers-to-blame-for-our-tech-dystopia-its-complicated?trk=feed_main-feed-card_feed-article-content&amp;amp;utm_campaign=even-with-a-silver-bullet-you-still-have-to-aim&amp;amp;utm_medium=referral&amp;amp;utm_source=productpicnic.beehiiv.com" target="_blank" rel=""&gt;a good layman’s overview&lt;/a&gt;&lt;/span&gt;&lt;span&gt; of how little a modern product is influenced by a given design decision, and how much is a consequence of business and technology decisions that stack up over time without a single decision-maker deliberately steering things to be so. I recommend giving this one a read, as a means of cognitive estrangement from the ways of working we take for granted, because we are too close to them to realize how ridiculous they really are. &lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;Unfortunately, many tech leaders do not take the time to reflect on whether the system actually makes sense. They shirk the responsibility given to them — to build an effective system — and instead &lt;/span&gt;&lt;span&gt;&lt;a href="https://www.linkedin.com/posts/udanium_designleadership-designethics-techculture-activity-7476357241084878848-h4Wa/?utm_campaign=even-with-a-silver-bullet-you-still-have-to-aim&amp;amp;utm_medium=referral&amp;amp;utm_source=productpicnic.beehiiv.com" target="_blank" rel=""&gt;whip the existing, faulty system&lt;/a&gt;&lt;/span&gt;&lt;span&gt; to run faster and faster, until all the wheels fall off:&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;p&gt;❝&lt;/p&gt;&lt;div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;“Ship more faster now” is not a product strategy; it’s a psychosis. …&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span&gt;Reframe craft as care for collaborators, users, and the collective aspiration to create something useful, meaningful, and significant. &lt;/span&gt;&lt;span&gt;&lt;strong&gt;Craft is a social act&lt;/strong&gt;&lt;/span&gt;&lt;span&gt; that binds teams around shared values and takes time.&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;But how do we make this reframe happen? How do we seize control of our discipline’s story?&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;That’s where my head’s been at for years — before the Picnic, before my work for NN/g, even before I started publishing with the UX Collective. But only lately have those thoughts come together into something actionable enough to share. I’ll be writing on this topic through July, but the capstone of these ideas will be my one-day workshop with Throughline on July 31st.&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;Flex those professional development budgets and join me in taking back control of the conversation. &lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;— Pavel at the Product Picnic&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/body&gt;&lt;/html&gt;</content>
        <author>
            <name>Pavel Samsonov</name>
        </author>
        <media:content medium="image" url="https://beehiiv-images-production.s3.amazonaws.com/uploads/asset/file/8df7d862-87ad-43f0-91fe-72ed4d3b57a9/74.png?t=1782685044"/>
    </entry>
    <entry>
        <id>tag:feedly.com,2013:cloud/entry/cOXRjoksGIQzU1pdqbdybn+OTWYeI0riptNneGckdsI=_19eeb80c989:771fcb:d67a104c</id>
        <title type="html">untitled</title>
        <published>2026-06-21T18:45:46Z</published>
        <updated>2026-06-21T18:45:50Z</updated>
        <link href="https://thinkinglabs.io/articles/2026/06/20/beyond-shades-of-conways-law-validation.html" rel="alternate" type="text/html"/>
        <content type="html">&lt;div&gt;&lt;body&gt;&lt;div&gt;&lt;article&gt;
&lt;p&gt;Moving beyond hunch and silencing the sceptics. Over the years, Conway’s Law has resurfaced as a guiding principle to organise teams. Yet, many people still hesitate to accept the idea. Ultimately, it remains a hypothesis. Melvin Conway did not provide any proof when publishing the thesis. However, in the meantime, decades later, a good deal of academic research supports the thesis. Ultimately, Harvard and MIT researchers provided robust empirical validation for the hypothesis across the software industry, further confirmed by the CHAOS Report from the Standish Group, reinforcing &lt;em&gt;The Mirroring Principle&lt;/em&gt; as an undeniable organisational reality.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Henderson and Clark observed in 1990 that established firms are unable to adopt architectural innovation because the architectural knowledge is embedded in the communication structures of the organisation, preventing them from adopting new designs.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;We show that architectural innovations destroy the usefulness of the architectural knowledge of established firms, and that since architectural knowledge tends to become embedded in the structure and information-processing procedures of established organizations, this destruction is difficult for firms to recognize and hard to correct. Architectural innovation therefore presents established organizations with subtle challenges that may have significant competitive implications.&lt;/p&gt;
&lt;p&gt;– &lt;a href="http://www.iot.ntnu.no/innovation/norsi-pims-courses/tushman/Handerson%20&amp;amp;%20Clark%20(1990).pdf"&gt;Architectural Innovation: The Reconfiguration of Existing Product Technologies and the Failure of Established Firms&lt;/a&gt;, Henderson and Clark, 1990&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;“&lt;em&gt;Architectural innovation&lt;/em&gt;” is defined as innovations that change the way product components are linked together, while leaving the core design concepts — and thus the basic knowledge underlying the components — untouched. That does not mean that components remain untouched. Often, architectural innovation is triggered by a change in a component that triggers new interactions and connections with other components.&lt;/p&gt;
&lt;p&gt;The study’s outcome is based on the analysis of 20 years of data (1962-1986) from the photolithographic alignment equipment industry, where four organisations subsequently took over market leadership because a competitor uncovered an architectural innovation that the previous leader was unable to detect due to its organisational structure.&lt;/p&gt;
&lt;p&gt;There has been growing evidence of numerous technical innovations that involved apparent modest changes to existing technology, but that had dramatic competitive consequences. In the mid-1950s, RCA developed a prototype for a portable radio receiver. It utilised technology that RCA mastered well. Yet, they did not pursue the idea. Until Sony, a small, relatively new company, entered the US market with portable radio receivers. RCA remained a follower. The irony was that Sony produced radios during many years using RCA’s licensed technology. The case of Xerox, in the mid-1970s, although the inventor of the plain-paper copier, was, during eight years of strategic errors, unable to compete with competitors offering smaller, more reliable copiers. Xerox lost half of the market. For a more recent example, we look at the German car industry, which had trouble marketing electric cars until Tesla, and later the Chinese car manufacturers took over the market. Meanwhile, Audi closes its Belgian factory that produces the expensive electric SUV because of a market mismatch.&lt;/p&gt;
&lt;p&gt;This inability to adopt architectural innovation happens because an organisation organises itself around the product’s key components that make up the “&lt;em&gt;dominant design&lt;/em&gt;”. The “&lt;em&gt;dominant design&lt;/em&gt;” is characterised by a general acceptance of a particular product architecture. It incorporates a range of basic design choices that are not revisited — think car platforms, or in software, a CRUD design. It results in communication channels between the design teams that reflect the organisation’s knowledge about the critical interactions between these components. Thus, an organisation’s communication channels embody the organisation’s architectural knowledge that is critical to effective design. From this moment on, organisations incline to focus only on “&lt;em&gt;incremental innovation&lt;/em&gt;”, tending to reinforce the competitive positions of established firms as it builds on their core competencies.&lt;/p&gt;
&lt;p&gt;As such, the architectural knowledge is a mirror of the communication structures organised around the product being designed. Somehow, this is the knowledge parallel of Conway’s thesis “&lt;em&gt;[Any] organisation which designs systems is constrained to produce designs which are copies of the communication structures of the organisation&lt;/em&gt;”. If communication structures dictate design (Conway, 1968), they also dictate what an organisation is capable of knowing (Henderson and Clark, 1990).&lt;/p&gt;
&lt;p&gt;Henderson and Clark establish that, given how knowledge is organised in firms, learning about changes in the product architecture is unlikely to happen. It requires explicit management, or even a different organisation. To counter this, the authors suggest cross-functional teams as a possible response to the danger of architectural knowledge becoming embedded within tacit communication lines.&lt;/p&gt;
&lt;p&gt;Recently, I was front-seat observing an organisation unable to run only a simple experiment, which would let them eventually discover a potential innovation, merely because of the structures in place.&lt;/p&gt;
&lt;p&gt;Because the communication channels are “frozen” around the old product architecture, the knowledge is also frozen; the organisation cannot distinguish or adjust to a possible new architecture reality, or even conceive a new design reality. This is Conway’s Law working back over time (more on this in &lt;em&gt;Dynamics: Conway’s Time Component&lt;/em&gt;).&lt;/p&gt;
&lt;h2&gt;The Aircraft Engine/Automotive Validations (2004, 2007)&lt;/h2&gt;
&lt;p&gt;In 2004, Sosa et al. published a study that investigated the design process of a commercial aircraft jet engine, the PW4098, at Pratt &amp;amp; Whitney. They studied how design interfaces in the product architecture map onto communication patterns within the development organisation. More specifically, they explored whether organisational problems exist at the boundaries of the components inside the jet engine, i.e. whether a misalignment exists between the design team boundaries and system component interfaces.&lt;/p&gt;
&lt;p&gt;According to Henderson and Clarke, architectural knowledge is embedded in the communication structures of organisations; therefore, organisations need to understand how they manage embedded knowledge. This is especially relevant when designing new products. In this context, system design interfaces are the primary sources of team interdependence, or at least, they should be. Meaning, when a specific team designs their own component with an interface to a neighboring component, there should be a corresponding technical interaction between the two respective teams. These are the expected cases. On the other hand, unmatched design interfaces and unmatched team interactions are unexpected. As it seems, these cases were largely ignored in previous research.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;However, we believe that considering these cases is important because their existence would indicate that not all known product-related interdependences are addressed by direct technical communication, and that technical communication (where not expected) may uncover undocumented product-related interdependences.&lt;/p&gt;
&lt;p&gt;– &lt;a href="http://users.ece.utexas.edu/~perry/education/382v-s08/papers/sosa.pdf"&gt;The Misalignment of Product Architecture and Organizational Structure in Complex Product Development&lt;/a&gt;, Sosa et al, 2004&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Finally, the study concludes that …&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;… we provide empirical evidence that product ambiguity exists, and it is more likely to be present across organizational and system boundaries&lt;/p&gt;
&lt;p&gt;– &lt;a href="http://users.ece.utexas.edu/~perry/education/382v-s08/papers/sosa.pdf"&gt;The Misalignment of Product Architecture and Organizational Structure in Complex Product Development&lt;/a&gt;, Sosa et al, 2004&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Meaning, that there is a great likelihood that some of the system component interfaces are not covered by team interactions, which can lead to major setbacks involving significant rework that can be extremely costly. The paper, exactly, refers to two major setbacks during the design of that specific jet engine.&lt;/p&gt;
&lt;p&gt;What they are essentially saying here is: &lt;strong&gt;If there is a misalignment between the organisation and the product architecture, there will be problems&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;In 2007, Gokpinar et al. conducted a study examining the design of cars in the automotive industry.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[…] a key challenge for product development organizations is matching the organization to the product being developed. This involves two fundamental problems: (1) How to assign people to the parts and subsystems that make up the product, and (2) How to ensure that people communicate/collaborate effectively in the performance of design tasks.&lt;/p&gt;
&lt;p&gt;– &lt;a href="https://citeseerx.ist.psu.edu/document?repid=rep1&amp;amp;type=pdf&amp;amp;doi=5553ae01b690837f755cd2c91fa6a4b7fdec6345"&gt;The Impact of Misalignment of Organization Structure and Product Architecture on Quality in Complex Product Development&lt;/a&gt;, Gokpinar et al, 2007&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The research defined a new metric &lt;em&gt;coordination deficit&lt;/em&gt;, which quantifies mismatches between product architecture and organisation structure, and investigated the effect of coordination deficit on product quality.&lt;/p&gt;
&lt;p&gt;They concluded that mismatches between product architecture and organisational structure are positively associated with quality problems.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Our results suggest that misalignment of the design organization with the product architecture negatively affects product quality”&lt;/p&gt;
&lt;p&gt;– &lt;a href="https://citeseerx.ist.psu.edu/document?repid=rep1&amp;amp;type=pdf&amp;amp;doi=5553ae01b690837f755cd2c91fa6a4b7fdec6345"&gt;The Impact of Misalignment of Organization Structure and Product Architecture on Quality in Complex Product Development&lt;/a&gt;, Gokpinar et al, 2007&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Once more, &lt;strong&gt;if there is a misalignment between organisation and product architecture, there will be problems&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;The Micro Software Validation (2006)&lt;/h2&gt;
&lt;p&gt;In 2006, Cataldo et al. investigated the consequences of congruence on the speed and efficiency of software development work inside a single software project. They investigated the impact of misalignment.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This is particularly important in product development organizations which organize themselves around their products’ architectures because the main components of their products define the organization’s key sub-tasks.&lt;/p&gt;
&lt;p&gt;– &lt;a href="https://www.cs.drexel.edu/~yfcai/CS680/Readings/Week8/Identification%20of%20Coordination%20Requirements.pdf"&gt;Identification of Coordination Requirements: Implications for the Design of Collaboration and Awareness Tools&lt;/a&gt;, Cataldo et al, 2006&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This matters because, as architectural knowledge is embedded in the communication structures of organisations (Henderson and Clark, 1990), any minor changes to the product architecture can disrupt the organisation’s ability to coordinate effectively.&lt;/p&gt;
&lt;p&gt;Ultimately, Cataldo et al. found that tasks were completed more rapidly when the patterns of communication between team members were congruent with the patterns of interdependency between components (more on &lt;em&gt;congruence&lt;/em&gt; in &lt;em&gt;Mechanics: The Mathematical &amp;amp; Geometrical Shades&lt;/em&gt;).&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Congruence&lt;/strong&gt; between coordination requirements and coordination activities shortened development time.&lt;/p&gt;
&lt;p&gt;– &lt;a href="https://www.cs.drexel.edu/~yfcai/CS680/Readings/Week8/Identification%20of%20Coordination%20Requirements.pdf"&gt;Identification of Coordination Requirements: Implications for the Design of Collaboration and Awareness Tools&lt;/a&gt;, Cataldo et al, 2006&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Fundamentally, the research indicates, &lt;strong&gt;if teams are aligned with the components they work on, teams are more efficient&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;The Macro Software Validation (2012)&lt;/h2&gt;
&lt;p&gt;In 2012, we had the first empirical evidence for the software industry provided by the research paper &lt;a href="https://www.hbs.edu/ris/Publication%20Files/08-039_1861e507-1dc1-4602-85b8-90d71559d85b.pdf"&gt;Exploring the Duality between Product and Organizational Architectures: A Test of the “Mirroring” Hypothesis&lt;/a&gt; from Baldwin et al.&lt;/p&gt;
&lt;p&gt;One of their findings was: software products tend to mirror the structure of the organisation in which they are developed.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;We find strong evidence to support the hypothesis that a product’s architecture tends to mirror the structure of the organization in which it is developed.&lt;/p&gt;
&lt;p&gt;– Exploring the Duality between Product and Organizational Architectures: A Test of the “Mirroring” Hypothesis, Baldwin, MacCormack and Rusnak, 2012&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img alt="Conway's Law Sketchplanations" src="https://thinkinglabs.io/images/shades-of-conways-law/sketchplanations-conways-law.jpg"&gt;&lt;/p&gt;
&lt;center&gt;&lt;i&gt;Source: Sketchplanations &lt;a href="https://sketchplanations.com/conways-law"&gt;https://sketchplanations.com/conways-law&lt;/a&gt;&lt;/i&gt;&lt;/center&gt;
&lt;p&gt;&lt;br&gt;&lt;/p&gt;
&lt;p&gt;To validate this hypothesis, they compared open-source with closed-source software. Based on the idea that the open-source communities are loosely coupled organisations by design because contributors have diverse goals, belong to different organisations, work in different geographical locations and time zones, and have no formal authority to guide development activities. Whereas closed-source organisations are more tightly-coupled, as they consist of smaller, co-located teams that share common goals, and are dedicated full-time to products and have formal decision-making authority to guide development.&lt;/p&gt;
&lt;p&gt;The study’s approach focused on comparing the architectures of open-source and closed-source software products that have similar functions and are of a similar size. They identified five software categories: financial management, word processing, spreadsheets, operating systems and databases. For each category, they selected an open-source and a closed-source software product.&lt;/p&gt;
&lt;p&gt;Because commercial firms are somehow reluctant to share their code base, especially for research comparing with “free” equivalents, researchers did not always have a closed-source codebase at their disposal. When commercial options were unavailable, they turned to formerly closed-source products that had been open-sourced. In those instances, they analysed the first open-source version.&lt;/p&gt;
&lt;p&gt;So they ended up comparing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;For financial management: GnuCash vs MyBooks&lt;/li&gt;
&lt;li&gt;For word processing: Abiword vs StarWriter&lt;/li&gt;
&lt;li&gt;For spreadsheets: Gnumeric vs StarCalc&lt;/li&gt;
&lt;li&gt;For operating systems: Linux vs Solaris&lt;/li&gt;
&lt;li&gt;For databases: MySQL vs Berkeley DB&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The paper primarily explores whether organisations with distinctly different forms develop products with distinctly different architectures.&lt;/p&gt;
&lt;p&gt;The outcome of the study was that &lt;strong&gt;loosely-coupled organisations, such as open-source, tend to develop products with a more modular architecture&lt;/strong&gt; than tightly-coupled organisations such as commercial firms. This confirms Parnas’ information hiding concept (Parnas 1972), which allows individual, isolated contributors to work independently. It also reaffirms Henderson and Clark’s observation. Loosely coupled, open-source organisations prevent architectural knowledge from becoming a central, siloed trap. They adopt cross-functional, loosely coupled teams to democratise knowledge. Tightly-coupled organisations, on the other hand, stumble when faced with innovations, because knowledge is tightly frozen, siloed, in the structures of the organisation.&lt;/p&gt;
&lt;h2&gt;The Industry Reality Check (1995-2020)&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;We know why projects fail, we know how to prevent their failure – so why do they still fail?&lt;/p&gt;
&lt;p&gt;– Cobb’s Paradox, Martin Cobb, CIO for the Secretariat of Treasury Board of Canada, CHAOS University, 1995, published in &lt;a href="https://www.inf.ufpr.br/urban/2019-1_205_e_220/205e220_Ler_ver_para_complementar/StandishGroup__UnfinishedVoyages-I.pdf"&gt;Unfinished Voyages I&lt;/a&gt;, Standish Group, 1995&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;When organisations keep treating software products as mere, rigid projects, the resulting architecture and outcomes for users will be notably poor, leading to surprising failures.&lt;/p&gt;
&lt;p&gt;From 1994 until 2020, the Standish Group published the CHAOS Report, a study on the success, failure, and challenge rates of IT projects.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Year&lt;/th&gt;
&lt;th&gt;Success&lt;/th&gt;
&lt;th&gt;Challenged&lt;/th&gt;
&lt;th&gt;Cancelled&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1994&lt;/td&gt;
&lt;td&gt;16%&lt;/td&gt;
&lt;td&gt;53%&lt;/td&gt;
&lt;td&gt;31%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2000&lt;/td&gt;
&lt;td&gt;28%&lt;/td&gt;
&lt;td&gt;49%&lt;/td&gt;
&lt;td&gt;23%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2002&lt;/td&gt;
&lt;td&gt;34%&lt;/td&gt;
&lt;td&gt;51%&lt;/td&gt;
&lt;td&gt;15%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2004&lt;/td&gt;
&lt;td&gt;29%&lt;/td&gt;
&lt;td&gt;53%&lt;/td&gt;
&lt;td&gt;18%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2006&lt;/td&gt;
&lt;td&gt;35%&lt;/td&gt;
&lt;td&gt;46%&lt;/td&gt;
&lt;td&gt;19%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2008&lt;/td&gt;
&lt;td&gt;32%&lt;/td&gt;
&lt;td&gt;44%&lt;/td&gt;
&lt;td&gt;24%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2011&lt;/td&gt;
&lt;td&gt;39%&lt;/td&gt;
&lt;td&gt;39%&lt;/td&gt;
&lt;td&gt;22%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2012&lt;/td&gt;
&lt;td&gt;37%&lt;/td&gt;
&lt;td&gt;46%&lt;/td&gt;
&lt;td&gt;17%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2013&lt;/td&gt;
&lt;td&gt;41%&lt;/td&gt;
&lt;td&gt;40%&lt;/td&gt;
&lt;td&gt;19%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2014&lt;/td&gt;
&lt;td&gt;36%&lt;/td&gt;
&lt;td&gt;47%&lt;/td&gt;
&lt;td&gt;17%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2015&lt;/td&gt;
&lt;td&gt;36%&lt;/td&gt;
&lt;td&gt;45%&lt;/td&gt;
&lt;td&gt;19%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2020&lt;/td&gt;
&lt;td&gt;31%&lt;/td&gt;
&lt;td&gt;50%&lt;/td&gt;
&lt;td&gt;19%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;em&gt;– source: CHAOS Reports 1995, 2009, 2015, 2020, Standish Group.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Although this may look baffling at first, this stagnation blindsides no experienced practitioners. The numbers reveal a flatline trend. Despite agile and DevOps, the success rate is capped at approximately 30%.&lt;/p&gt;
&lt;p&gt;Till 2015, the Standish Group focused mainly on classic project management requirements to measure success, such as well-defined upfront requirements, proper planning, skilled project managers, as well as user involvement and project sponsor. Success was defined in classic PMI terms, the &lt;a href="https://en.wikipedia.org/wiki/Project_management_triangle"&gt;Iron Triangle&lt;/a&gt;, i.e. on time, on budget, with all features as initially specified. Then, in 2015, a first significant shift happened. The success resolution definition changed. It was still on time and on budget, however, with satisfactory results. All requirements no longer have to be implemented, since data shows that some projects meet the Iron Triangle yet do not return value. In the end, satisfaction and value are greater when fewer features are delivered, but meeting obvious user needs. This is aligned with Lean principles, as well as another Standish Group study revealing &lt;a href="https://www.mountaingoatsoftware.com/blog/are-64-of-features-really-rarely-or-never-used"&gt;that 64% of delivered features are rarely used&lt;/a&gt;. Later confirmed by the 2019 &lt;a href="https://www.pendo.io/resources/the-2019-feature-adoption-report/"&gt;Pendo Feature Adoption Study&lt;/a&gt;, revealing 80% of features see low to zero adoption.&lt;/p&gt;
&lt;p&gt;By 2020, the Standish Group had pivoted and reported an astonishing outcome that contradicts their early recommendations. Stop treating software products as a project because, by definition, projects have a start and an end, but products do &lt;em&gt;not&lt;/em&gt;. They explicitly stated that &lt;a href="https://medium.com/leadership-and-agility/project-managers-fail-to-help-software-projects-standish-group-chaos-2020-e65d803e99f2"&gt;project managers harm software products&lt;/a&gt; and increase the failure rate. Specifically, the report demonstrates that project managers often generate more paperwork, resulting in slower decision-making that inevitably slows down feedback. While, once more, not surprising for experienced practitioners — it was already established long before, and brought to the public in 2017 with the &lt;a href="https://www.allankelly.net/archives/4796/what-ever-happened-to-noprojects-post-projects/"&gt;#NoProjects movement&lt;/a&gt; — the Standish Group brought it to the masses.&lt;/p&gt;
&lt;p&gt;Ultimately, the Standish Group concluded that project success is defined by &lt;em&gt;Good Sponsor&lt;/em&gt;, &lt;em&gt;Good Team&lt;/em&gt;, &lt;em&gt;Good Place&lt;/em&gt;, and &lt;em&gt;Short Decision Latency&lt;/em&gt;. To a large extent, this aligns with the 2001 findings from the book &lt;a href="https://app.thestorygraph.com/books/1771dbe4-16a3-4316-83a1-ed2b21984bc9"&gt;Good to Great&lt;/a&gt;. Organisations become great when they have &lt;em&gt;Level 5 Leadership&lt;/em&gt; (Good Sponsor) to build enduring greatness through a paradoxical blend of personal humility and professional will. They focus on &lt;em&gt;First Who … Then What&lt;/em&gt; (Good Team), first securing the right people before figuring out where to drive it, before vision, before strategy, before tactics, before organisational structure, before technology. Lastly, they &lt;em&gt;Confront the Brutal Facts of Reality&lt;/em&gt; (Good Place), by fostering a climate where the truth is heard.&lt;/p&gt;
&lt;p&gt;These crucial prerequisites enable &lt;em&gt;Short Decision Latency&lt;/em&gt;, allowing information to circulate rapidly. However, low decision latency is entirely dependent on communication paths. Since Conway’s Law dictates that systems reflect the organisation’s communication structures, high-latency organisations stuck in silos are unable to produce high-velocity, decoupled system designs. This architectural congestion hampers communication and impedes overall success.&lt;/p&gt;
&lt;p&gt;Ultimately, the CHAOS Report recommends moving away from “projects” and adopting Infinite Flow, which Lean has been promoting since the 1980’s. Somehow, this is the business world finally accepting what Baldwin et al. proved in 2012: tightly coupled organisations produce tightly coupled system architectures that work against flow, while loosely-coupled organisations thrive because they produce loosely coupled system architectures that enable flow, short time to markets, and consequently accelerated feedback to meet user expectations better. The 2020 CHAOS Report &lt;em&gt;Good Place&lt;/em&gt; — where truth is heard to reduce Decision Latency — is exactly the type of environment needed to break the “frozen”, siloed, tacit communication lines Henderson and Clark blamed for corporate blindness.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;To conclude, the tech industry spent decades trying to fix management processes, only to realise they were fighting a losing battle against the structural gravity of Conway’s Law and its implications on innovation and market leadership. Mediocrity is the default. Success is optional. Just saying …&lt;/p&gt;
&lt;h2&gt;The Series: Navigating the Shades&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://thinkinglabs.io/articles/2026/04/24/beyond-the-shades-of-conways-law.html"&gt;Beyond the Shades of Conway’s Law series&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://thinkinglabs.io/articles/2026/06/07/beyond-shades-of-conways-law-foundations.html"&gt;Foundations: The Origin &amp;amp; The Mirroring Principle&lt;/a&gt; - How the worlds of organisation and product design observed the same thesis independently.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Validation: The Research &amp;amp; Reality Check&lt;/strong&gt; - Moving beyond the “hunch”, how researchers proved the Law in different industries, but especially in software.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mechanics: The Mathematical &amp;amp; Geometrical Shades&lt;/strong&gt; - The geometry of design: from mathematical isomorphism, homomorphism, congruence to compatibility.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Strategy: Reversing the Law&lt;/strong&gt; - How the system ultimately forces the organisation to change versus deliberately changing the organisation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scale: Conway’s Corollary&lt;/strong&gt; - The required organisational flexibility.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dynamics: Conway’s Time Component&lt;/strong&gt; - The “Engineer Half Life” and why architecture is “sticky” long after teams change.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Conclusion: The Different Lenses&lt;/strong&gt; - A concluding look at how we perceive organisations and their systems.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Bibliography&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.melconway.com/Home/Committees_Paper.html"&gt;How Do Committees Invent?&lt;/a&gt;, Melvin Conway, 1968&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.win.tue.nl/~wstomv/edu/2ip30/references/criteria_for_modularization.pdf"&gt;On the Criteria To Be Used in Decomposing Systems into Modules&lt;/a&gt;, Parnas, 1972&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.iot.ntnu.no/innovation/norsi-pims-courses/tushman/Handerson%20&amp;amp;%20Clark%20(1990).pdf"&gt;Architectural Innovation: The Reconfiguration of Existing Product Technologies and the Failure of Established Firms&lt;/a&gt;, Henderson and Clark, 1990&lt;/li&gt;
&lt;li&gt;&lt;a href="https://personal.utdallas.edu/~chung/SYSM6309/chaos_report.pdf"&gt;CHAOS Report 1995&lt;/a&gt;, Standish Group, 1995&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.inf.ufpr.br/urban/2019-1_205_e_220/205e220_Ler_ver_para_complementar/StandishGroup__UnfinishedVoyages-I.pdf"&gt;Unfinished Voyages I&lt;/a&gt;, Standish Group, 1995&lt;/li&gt;
&lt;li&gt;&lt;a href="https://app.thestorygraph.com/books/1771dbe4-16a3-4316-83a1-ed2b21984bc9"&gt;Good to Great&lt;/a&gt;, Jim Collins, 2001&lt;/li&gt;
&lt;li&gt;&lt;a href="http://users.ece.utexas.edu/~perry/education/382v-s08/papers/sosa.pdf"&gt;The Misalignment of Product Architecture and Organizational Structure in Complex Product Development&lt;/a&gt;, Sosa et al, 2004&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.cs.drexel.edu/~yfcai/CS680/Readings/Week8/Identification%20of%20Coordination%20Requirements.pdf"&gt;Identification of Coordination Requirements: Implications for the Design of Collaboration and Awareness Tools&lt;/a&gt;, Cataldo 2006&lt;/li&gt;
&lt;li&gt;&lt;a href="https://citeseerx.ist.psu.edu/document?repid=rep1&amp;amp;type=pdf&amp;amp;doi=5553ae01b690837f755cd2c91fa6a4b7fdec6345"&gt;The Impact of Misalignment of Organization Structure and Product Architecture on Quality in Complex Product Development&lt;/a&gt;, Gokpinar et al, 2007&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.classes.cs.uchicago.edu/archive/2014/fall/51210-1/required.reading/Standish.Group.Chaos.2009.pdf"&gt;CHAOS Report 2009&lt;/a&gt;, Standish Group, 2009&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.hbs.edu/ris/Publication%20Files/08-039_1861e507-1dc1-4602-85b8-90d71559d85b.pdf"&gt;Exploring the Duality between Product and Organizational Architecture: A Test of the “Mirroring” Hypothesis&lt;/a&gt;, Baldwin, MacCormack, Rusnak, 2012&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cdn1-public.infotech.com/agile/CHAOSReport2015-Final.pdf"&gt;CHAOS Report 2015&lt;/a&gt;, Standish Group, 2015&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.infoq.com/articles/standish-chaos-2015/"&gt;Standish Group 2015 Chaos Report - Q&amp;amp;A with Jennifer Lynch&lt;/a&gt;, InnoQ, 2015&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.mountaingoatsoftware.com/blog/are-64-of-features-really-rarely-or-never-used"&gt;Are 64% of Features Really Rarely or Never Used?&lt;/a&gt;, Mike Cohn, 2016&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pendo.io/resources/the-2019-feature-adoption-report/"&gt;The 2019 Feature Adoption Report&lt;/a&gt;, Pendo, 2019&lt;/li&gt;
&lt;li&gt;&lt;a href="https://thestory.is/en/journal/chaos-report/"&gt;Chaos Report — why this study about IT project management is so unique&lt;/a&gt; about the CHAOS Report 2020, Radek, The Story, 2024&lt;/li&gt;
&lt;/ul&gt;
&lt;/article&gt;
&lt;/div&gt;&lt;/body&gt;&lt;/div&gt;</content>
        <author>
            <name/>
        </author>
        <media:content medium="image" url="https://thinkinglabs.io/images/shades-of-conways-law/sketchplanations-conways-law.jpg"/>
        <source>
            <id>tag:feedly.com,2013:cloud/feed/https://thinkinglabs.io/feed.xml</id>
            <title type="html">ThinkingLabs:: Thierry de Pauw</title>
            <link href="https://thinkinglabs.io" rel="alternate" type="text/html"/>
            <updated>2026-06-21T18:45:50Z</updated>
        </source>
    </entry>
    <entry>
        <id>tag:feedly.com,2013:cloud/entry/cOXRjoksGIQzU1pdqbdybn+OTWYeI0riptNneGckdsI=_19ec6e6229f:633c44:5df5eb75</id>
        <title type="html">untitled</title>
        <published>2026-06-14T16:10:31Z</published>
        <updated>2026-06-14T16:10:37Z</updated>
        <link href="https://www.funnyshit.com.au/the_plan.html" rel="alternate" type="text/html"/>
        <content type="html">&lt;div&gt;&lt;body&gt;&lt;div&gt;&lt;div&gt;&lt;h1&gt;The Plan&lt;/h1&gt;
&lt;p&gt;In the beginning was the Plan.&lt;/p&gt;
&lt;p&gt;And then came the Assumptions.&lt;/p&gt;
&lt;p&gt;And the Assumptions were without form.&lt;/p&gt;
&lt;p&gt;And darkness was upon the face of the Workers.&lt;/p&gt;
&lt;p&gt;And they spoke among themselves, saying, "It is a crock of shit, and it
stinketh."&lt;/p&gt;
&lt;p&gt; And the workers went unto their Supervisors and said, "It is a pail of
dung, and none may abide the odour thereof."&lt;/p&gt;
&lt;p&gt; And the Supervisors went unto their Managers, saying, "It is a container
of excrement, and it is very strong, such that none may abide by it."&lt;/p&gt;
&lt;p&gt; And the Managers went unto their Directors, saying, "It is a vessel of
fertiliser, and none may abide its strength."&lt;/p&gt;
&lt;p&gt; And the Directors spoke amongst themselves, saying one to another, "It
contains that which aids plant growth, and it is very strong."&lt;/p&gt;
&lt;p&gt;And the Directors then went onto the Vice Presidents, saying unto them, "It
promotes growth and is very powerful."&lt;/p&gt;
&lt;p&gt;And the Vice Presidents went unto the President, saying unto him, "This
new plan will actively promote the growth and vigour of the company; with powerful
effects."&lt;/p&gt;
&lt;p&gt;And the President looked upon the Plan, and saw that it was good.&lt;/p&gt;
&lt;p&gt;And the Plan became Policy.&lt;/p&gt;
&lt;p&gt;This is How Shit Happens.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.funnyshit.com.au/"&gt;→ Check out more Funny Shit&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/body&gt;&lt;/div&gt;</content>
        <author>
            <name/>
        </author>
    </entry>
    <entry>
        <id>tag:feedly.com,2013:cloud/entry/cOXRjoksGIQzU1pdqbdybn+OTWYeI0riptNneGckdsI=_19ec4cf4358:49c447:b0e60e29</id>
        <title type="html">untitled</title>
        <published>2026-06-14T06:26:18Z</published>
        <updated>2026-06-14T06:26:22Z</updated>
        <link href="https://www.psychologytoday.com/gb/blog/creating-successful-change/202606/why-its-so-hard-to-know-if-youre-really-making-progress" rel="alternate" type="text/html"/>
        <content type="html">&lt;div&gt;&lt;body&gt;&lt;div&gt;&lt;div&gt;
&lt;p&gt;Think about the last time you tracked your progress on a personal goal. Maybe you were trying to exercise more frequently, be more patient with a spouse or partner, or learn a new skill. Chances are, you had a rough sense of how it was going. And chances are that sense was more &lt;a hreflang="en" href="https://www.psychologytoday.com/gb/basics/optimism" title="Psychology Today looks at optimistic"&gt;optimistic&lt;/a&gt; than the evidence warranted.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;This is not a character flaw. It is one of the most reliable findings in behavioral science: We are systematically poor judges of our own progress, and during periods of active change, we tend to get worse.&lt;/p&gt;
&lt;p&gt;One reason is what psychologists Terence Mitchell and Leigh Thompson at the University of Washington termed rosy retrospection. This is our consistent tendency to remember past experiences more favorably than we rated them in the moment. When we look back over a month of trying to exercise more or sleep differently, our &lt;a hreflang="en" href="https://www.psychologytoday.com/gb/basics/memory" title="Psychology Today looks at memory"&gt;memory&lt;/a&gt; selectively surfaces the days we succeeded. The days we failed are there, but they are not as memorable. We feel we’ve been doing better than we really have.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;A second explanation is subtler. &lt;a hreflang="en" href="https://www.psychologytoday.com/gb/basics/motivation" title="Psychology Today looks at Motivation"&gt;Motivation&lt;/a&gt; isn’t a fixed state; it shifts gradually, often well before behavior changes in any visible way. The enthusiasm that felt solid in January has usually started to erode by March. But because the erosion is incremental, we rarely catch it in real time. We trust that how we feel today is roughly how we’ve been feeling all along. It almost never is.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;Together, these two patterns create a specific failure mode: We assume the feedback loop is running when it isn’t. We trust that because we know our own goals and intentions, we know how we’re actually doing. But intention and behavior are not the same thing. How we feel about a change is not the same as how we’re enacting it. And until we close that gap with something more rigorous than a gut check, we’re optimizing for a version of our progress that may not exist.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;In researching what separates change successes from failures at organizations for my book, my coauthors and I found that leaders designing change were consistently more confident about employee progress on change than the employees’ actual behavior or stated experience supported. They trusted their read on the room. The data, when they gathered it, told a different story. The wider the gap, the more likely the change failure.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;The same gap operates in personal change. And the same remedy applies: Use measurement, not instinct.&lt;/p&gt;
&lt;p&gt;This doesn’t require an elaborate system. Research by James Pennebaker at the University of Texas at Austin shows that the act of writing specifically about your experience—not vague journaling, but naming exactly what you did, how it felt, and where the friction was—produces measurable improvements in self-understanding and in the likelihood of follow-through. Writing forces the brain to translate impression into information. The gap between what you felt and what actually happened becomes clearer.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;Social accountability produces a related effect. A study by psychologist Gail Matthews at Dominican University found that people who wrote down their goals and reported progress to a friend were 42 percent more likely to achieve those goals than people who kept them private. Part of what accountability does is discipline the story you tell yourself. You can’t smooth over the gaps as easily when someone else is watching for them.&lt;/p&gt;

&lt;p&gt;Both interventions do the same thing: They replace vague impressions with actual information. When people begin gathering that information honestly, they usually discover not only the gaps in their efforts, but also the progress they had stopped noticing.&lt;/p&gt;
&lt;p&gt;Teresa Amabile, a psychologist at Harvard Business School, spent years studying what helps people stay motivated during sustained effort. Her research, drawn from the daily diaries of 238 professionals tracked over several months, produced a counterintuitive finding: The single biggest day-to-day motivator wasn’t recognition from a manager or a meaningful reward. It was the perception of making progress on work that mattered. Small wins, when noticed specifically, produced outsized improvements in engagement and follow-through. The operative word is “noticed.” Progress that goes unobserved doesn’t produce the same effect. It needs to be named to become fuel.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;This is what honest self-assessment makes possible. When you journal about your week in specific detail, you often discover you accomplished much less than your vague, optimistic impression suggested—and you'll have a record you can point to as concrete evidence. That specificity matters more than it might seem. Ayelet Fishbach at the University of Chicago Booth School of Business has shown across repeated experiments that concrete progress feedback strengthens goal commitment more than encouragement does. What keeps people going isn’t being told they’re doing well. It’s seeing, with some precision, that they truly are.&lt;/p&gt;
&lt;div&gt;
&lt;p&gt;Motivation Essential Reads&lt;/p&gt;

&lt;/div&gt;
&lt;p&gt;The story you’re telling yourself about your progress probably has some blind spots. But it may also be overlooking real growth that felt too small or too ordinary to count. Learning to see your progress more clearly, without judgment, isn’t self-&lt;a hreflang="en" href="https://www.psychologytoday.com/gb/basics/punishment" title="Psychology Today looks at punishment"&gt;punishment&lt;/a&gt;. It’s an invaluable form of self-support.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/body&gt;&lt;/div&gt;</content>
        <author>
            <name/>
        </author>
        <media:content medium="image" url="http://www.googletagmanager.com/ns.html?id=GTM-NW5PKS"/>
    </entry>
    <entry>
        <id>tag:feedly.com,2013:cloud/entry/cOXRjoksGIQzU1pdqbdybn+OTWYeI0riptNneGckdsI=_19eb821c9a4:1c44b1:ac72f017</id>
        <title type="html">untitled</title>
        <published>2026-06-11T19:21:22Z</published>
        <updated>2026-06-11T19:21:25Z</updated>
        <link href="https://mixpanel.com/blog/ai-adoption-gap/" rel="alternate" type="text/html"/>
        <content type="html">&lt;div&gt;&lt;body&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;Chances are you used an AI tool before 9 a.m. today. Chances are most of your users didn't.&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;It's a simple contrast, but Debbie McMahon, VP of Product at &lt;a rel="noreferrer noopener" href="https://www.loveholidays.ie/"&gt;Loveholidays&lt;/a&gt;, built an entire &lt;a href="https://mixpanel.com/mxp/mxp-2026"&gt;MXP London&lt;/a&gt; session around it and what it means for every product decision. She called it the AI adoption gap, and she was refreshingly clear-eyed about the ways it had distorted her own judgment.&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;h2&gt;&lt;span&gt;The AI adoption gap and the 0.04%&lt;/span&gt;&lt;/h2&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;An infographic Debbie shared on stage breaks the world's relationship with AI into four tiers:&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;ul&gt;&lt;span&gt;&lt;li&gt;&lt;strong&gt;84%&lt;/strong&gt; of people have never used AI&lt;/li&gt;&lt;li&gt;&lt;strong&gt;16%&lt;/strong&gt; have tried a free chatbot&lt;/li&gt;&lt;li&gt;&lt;strong&gt;0.3%&lt;/strong&gt; pay for AI&lt;/li&gt;&lt;li&gt;&lt;strong&gt;0.04%&lt;/strong&gt; are actively building with it&lt;/li&gt;&lt;/span&gt;&lt;/ul&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;That last group is the one that fills rooms like MXP London. And Debbie's point is that this creates a fundamental disconnect. The people designing AI-powered products are a statistical anomaly relative to the people they're designing for.&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;She made that concrete with a story about her friend Agnes. Agnes is a primary school teacher who spends her days helping children from difficult family circumstances settle into school. She's smart, busy, and has a free ChatGPT account she’s never used. Why? Her school doesn't allow AI tools on work devices. The budget isn't there for anything paid. And nobody on staff is confident enough with the technology to know where to start, even if the first two problems disappeared tomorrow.&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;Agnes is not an edge case. She's a typical Loveholidays customer, and she's who Debbie asked the MXP London audience to hold in mind.&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;



&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;span&gt;“&lt;/span&gt;
&lt;p&gt;We're living in a bubble. We're the 0.04% and our daily experience of AI has essentially nothing to do with our users’ reality.&lt;span&gt;”&lt;/span&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p&gt;Debbie McMahon&lt;/p&gt;
&lt;p&gt;VP of Product, Loveholidays&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;&lt;em&gt;For a look at how AI engagement is trending across real products, Mixpanel's &lt;a rel="noreferrer noopener" href="https://mixpanel.com/blog/ai-benchmarks-2026/"&gt;2026 AI benchmarks&lt;/a&gt; draw on nearly 290 billion AI events across 2.6 billion devices, and the picture is more nuanced than adoption headlines suggest.&lt;/em&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;h2&gt;&lt;span&gt;Three ways the bubble distorts your decisions&lt;/span&gt;&lt;/h2&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;Debbie named three patterns she sees in herself and across the industry.&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;&lt;strong&gt;Over-prioritizing AI features.&lt;/strong&gt; "Have you put something out there just because it was easy to do?" She raised her own hand. The pressure is real: boards want AI in the roadmap, investors want AI in the roadmap, competitors are shipping. And the tooling makes it fast to build something. But fast to build isn't the same as worth building.&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;&lt;strong&gt;Underestimating friction.&lt;/strong&gt; Most people are forming their views on AI right now without the benefit of product communities or conference sessions to help them process it. That's not a knock on users. They're figuring out whether to trust the technology at the same moment they're being asked to use it. Dropping a disclaimer like "generated by AI, so may not be accurate" into a set of results doesn't help someone who's already uncertain about the output.&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;&lt;strong&gt;Asking users to change behavior.&lt;/strong&gt; Behavior change is extraordinarily difficult even when people want to change. For users with an ingrained habit and no clear reason to do anything differently, it's close to impossible. The customers who are confused or skeptical about AI aren't going to reroute their entire search behavior for a feature they weren't asking for. If what they want is a keyword search and a filter, that's what they'll reach for.&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;

&lt;div&gt;
&lt;div&gt;
&lt;p&gt;Go deeper&lt;/p&gt;
&lt;p&gt;See whether your AI features are delivering value, or just getting used:&lt;/p&gt;


&lt;/div&gt;
&lt;/div&gt;
&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;h2&gt;&lt;span&gt;What the data actually showed&lt;/span&gt;&lt;/h2&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;Two case studies from Loveholidays that Debbie shared with the kind of candor that makes MXP sessions worth attending.&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;&lt;strong&gt;The room grouping problem.&lt;/strong&gt; Hotel listings at Loveholidays had accumulated a long tail of duplicated, poorly named room types, a messy, years-old problem that had resisted every previous attempt to fix it. When a team went after it with AI, they went in with confidence. What they found was that the problem was deterministic: two rooms are either the same or they're not, and AI isn't built for that kind of precision. The model grouped rooms in ways that didn't hold up to scrutiny, renamed options customers recognized, and quietly dropped listings that people had been booking. The output looked coherent, but it wasn't. &lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;In Debbie’s own words: "Don't put AI on top of a broken thing. Fix the actual problem."&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;&lt;strong&gt;The Q&amp;amp;A tool.&lt;/strong&gt; Another team shipped an LLM-based Q&amp;amp;A feature into the pre-booking journey, built around the hypothesis that customers comparing hotels would want to ask questions. The feature got used, a lot, actually. But when the team looked at who was using it, the data didn't match the hypothesis at all.&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;The users weren't pre-booking customers weighing their options. They were people who had already made a booking, navigating a long and confusing post-booking experience to find basic information about their upcoming trip. And the questions they were asking weren't the ones the team had imagined. The top two were whether their room came with a kettle and whether it had an iron. Third most common: the wi-fi password.&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;In other words, customers who needed information Loveholidays already had were threading through a complex AI-powered feature just to ask if they needed to pack a travel iron. The team proposed moving the tool into the post-booking journey where the actual demand was. Debbie shut it down, and the reasoning is worth sitting with.&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;



&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;span&gt;“&lt;/span&gt;
&lt;p&gt;Just because it does answer those users’ questions doesn't mean that this is the right solution. We have that information. It’s a fact. We just need to give it to them in a form that they need it in.&lt;span&gt;”&lt;/span&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p&gt;Debbie McMahon&lt;/p&gt;
&lt;p&gt;VP of Product, Loveholidays&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;The post-booking journey got fixed instead, and the Q&amp;amp;A tool got pulled. The story doesn't end there: the team is relaunching the feature with a genuinely different hypothesis behind it. Since that original experiment, Loveholidays launched its own reviews platform, which changes what a Q&amp;amp;A tool can meaningfully do and who it's actually for. There's a real use case now tied to a specific user group, and that's what "not now" looks like when it's used well.&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;

&lt;div&gt;
&lt;div&gt;
&lt;p&gt;Go deeper&lt;/p&gt;
&lt;p&gt;Further reading on building and measuring product adoption in the AI era:&lt;/p&gt;


&lt;/div&gt;
&lt;/div&gt;
&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;h2&gt;&lt;span&gt;Building different journeys for different people&lt;/span&gt;&lt;/h2&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;Loveholidays went to their customers directly and asked how they'd feel about AI-mediated booking experiences. The words that came back included "anxiety," "I trust filters more," and "I prefer clicking." There was also genuine enthusiasm from a portion of respondents. But the skepticism was real, present across a significant share of the audience, and Debbie didn't try to explain it away.&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;&lt;a rel="noreferrer noopener" href="https://www.gartner.com/en/newsroom/press-releases/2025-09-03-gartner-survey-finds-53-percent-of-consumers-distrust-ai-powered-search-results0"&gt;53% of consumers distrust AI-powered search results&lt;/a&gt;, according to a Gartner survey published in September 2025. Debbie cited a similar figure on stage and her read was plain: "I can't ignore that. That’s the reality for my customers, and that's where we're starting from."&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;Her answer is to segment more precisely. AI comfort and interest now sit alongside demographics, holiday type, and referral route as a dimension Debbie's team uses to personalize the experience. Design one AI-mediated journey for everyone and you either hold back the users who want to explore new things or push unwanted change onto the customers who aren't ready for it. &lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;Debbie's dad started using email about a decade after she did. She uses that as a reference point: adoption follows its own timeline, and you can't compress it by shipping a feature and calling it done.&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;h2&gt;&lt;span&gt;The playground: A structural answer&lt;/span&gt;&lt;/h2&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;Recognizing a problem clearly is useful. Building an organizational system to address it at scale is something else. That's what separates this MXP session from a general mindset piece.&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;Debbie's team built what she calls "out the bubble," an internal prototyping environment that anyone at Loveholidays with access to Codex or Claude Code can use, with no prior technical setup required. It's pre-integrated with the company's design system, data mesh, live pricing, and real images, which matters more than it might sound. When you put a prototype in front of a customer in a travel context, the first thing they notice is whether the hotel price looks real. This system removes that distraction so the feedback is about the experience itself.&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;The pipeline works in three stages:&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;ul&gt;&lt;span&gt;&lt;li&gt;Anyone at the company builds a prototype, sometimes in 10 minutes, sometimes a couple of hours, and pushes it to an internal testing environment for NMD review.&lt;/li&gt;&lt;li&gt;Prototypes that clear that bar are automatically routed to Usertesting.com, with the builder setting up the user panel themselves, no dependency on a separate research team.&lt;/li&gt;&lt;li&gt;The ones that pass user testing move to a small live test, pushed out via socials, CRM, or the homepage to a defined customer segment.&lt;/li&gt;&lt;/span&gt;&lt;/ul&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;The important shift isn't the speed, though. It's that the people with the best product ideas are no longer gated by their ability to build prototypes. The system makes that capability available to the whole company. Fewer ideas get duplicated. More of them get in front of real customers. And when something earns the full investment of a real build, there's actual evidence behind the decision.&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;h2&gt;&lt;span&gt;Start with the problem. The tools will follow.&lt;/span&gt;&lt;/h2&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;Debbie closed by revisiting the Henry Ford quote, carefully, because she's not entirely sure Ford said it. But the argument holds regardless. The car achieved adoption because Ford understood what his customers actually needed. He built a faster horse, not a different animal entirely.&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;



&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;span&gt;“&lt;/span&gt;
&lt;p&gt;AI doesn't let us skip understanding what our users need. If you want people to adopt things, you have to start with their problem.&lt;span&gt;”&lt;/span&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p&gt;Debbie McMahon&lt;/p&gt;
&lt;p&gt;VP of Product, Loveholidays&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;The tools have changed. The product job hasn't. What AI does change is how big your answers can be once you've understood the question clearly. The potential is genuinely extraordinary, but only after you've done the harder work of understanding what your users need and why they'd change.&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;Remember Agnes from the opening of this piece? The primary school teacher who supports children through difficult family circumstances, has a ChatGPT account she never uses, and has no budget, no tech support, and no time to figure it out herself. She's never going to ask for an AI-powered solution to her problems. But she'd benefit enormously if someone took the time to understand those problems and built something that addressed them, with AI as part of the answer rather than the starting point. &lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;That's what good product work looks like, and as Debbie put it, that's always been the job.&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;h2&gt;&lt;span&gt;Build the bridge your users are ready to cross&lt;/span&gt;&lt;/h2&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;The product teams pulling ahead right now aren't the ones shipping the most AI features. They're the ones who understand the gap between their own relationship with AI and their users', and who've built the systems to keep closing it.&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;To understand what your users are doing in your product, &lt;a rel="noreferrer noopener" href="https://mixpanel.com/ai"&gt;Mixpanel AI&lt;/a&gt; is built to surface that signal proactively, so the insight finds you rather than the other way around. For technical teams who want to go further, &lt;a rel="noreferrer noopener" href="https://mixpanel.com/blog/mixpanel-headless/"&gt;try Mixpanel Headless&lt;/a&gt; where AI agents read and drive Mixpanel programmatically.&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/div&gt;&lt;/body&gt;&lt;/div&gt;</content>
        <author>
            <name/>
        </author>
    </entry>
    <entry>
        <id>tag:feedly.com,2013:cloud/entry/cOXRjoksGIQzU1pdqbdybn+OTWYeI0riptNneGckdsI=_19e83d95682:e7fa0:6797f8b7</id>
        <title type="html">Social RSS (?)</title>
        <published>2026-06-01T15:41:59Z</published>
        <updated>2026-06-01T15:42:03Z</updated>
        <link href="https://chriscoyier.net/2026/06/01/social-rss-2/" rel="alternate" type="text/html"/>
        <summary type="html">What’s up with this? The spirit, of course, is “I want my Google Reader back.” I should be careful though: I imagine if we really did have it back exactly as it was, it would prob…</summary>
        <content type="html">&lt;!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"&gt;
&lt;html&gt;&lt;body&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;
        
&lt;p class="wp-block-paragraph"&gt;What’s up with this?&lt;/p&gt;



&lt;figure class="wp-block-embed is-type-rich is-provider-bluesky-social wp-block-embed-bluesky-social"&gt;&lt;/figure&gt;&lt;p class="wp-block-paragraph"&gt;The spirit, of course, is “I want my Google Reader back.” &lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;I should be careful though: I imagine if we really did have it back exactly as it was, it would probably not be as cool as we remember. That was a long-ass time ago and web software just wasn’t as nice as it is now. But: it &lt;em&gt;really did&lt;/em&gt; have social features in it! I could leave comments and see comments from my friends. (How “friends” worked back then, I scarcely remember.)&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;I’m not alone in wanting this. Here’s what I’ve seen so far.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;There is &lt;a href="https://skyreader.app/"&gt;Skyreader&lt;/a&gt;, and it looks like Tim Disney is still actively working on it:&lt;/p&gt;



&lt;figure class="wp-block-embed is-type-rich is-provider-bluesky-social wp-block-embed-bluesky-social"&gt;&lt;/figure&gt;&lt;p class="wp-block-paragraph"&gt;In my mind (and perhaps not reality?) Skyreader solves a “cold start” problem where signing up for a new social site is a lonely bummer because you don’t have any friends. Well, if all my Bluesky friends were automatically my friends on Skyreader, wouldn’t that be, like, good? &lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;My problem is… I don’t… get it. &lt;/p&gt;



&lt;ul class="wp-block-list"&gt;&lt;li&gt;Maybe there aren’t really “friends” on Skyreader? If there are, I can’t really find a list of them. If there aren’t, I guess this isn’t what I’m looking for. Or is it just assumed they are the same as Bluesky friends? I dunno, I think I have a lot to learn about this AT Proto stuff. &lt;/li&gt;



&lt;li&gt;What happens when I share an article? Does it share on my Bluesky? It doesn’t look like it. Who sees my shared articles then? My friends, if there are such a thing? Other people who explicitly subscribe? How would anyone figure out how to do that?&lt;/li&gt;



&lt;li&gt;It looks like I can share and I can highlight stuff specifically in what I share. Who sees the highlight? I imagine they need to use Skyreader to see that highlight? Or does it republish as RSS somehow?&lt;/li&gt;



&lt;li&gt;No comments… right? That’s weird to me for a social feed reader. What I think of when I think &lt;strong&gt;social feed reader&lt;/strong&gt; is 90% writing and reading my friends comments.&lt;/li&gt;



&lt;li&gt;The UI is confusing to me. I don’t love the expanding list format that jumps around a lot.&lt;/li&gt;
&lt;/ul&gt;&lt;p class="wp-block-paragraph"&gt;The main reason I can’t “really use it,” though, is that it doesn’t sync with Feedbin. I understand that’s a niche concern, but I need &lt;em&gt;one&lt;/em&gt; canonical feed source, so everything I’m subscribed to is in one place, and how much I’ve read is also canonical. That might be antithetical to AT Proto? I have no idea.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;&lt;a href="https://indieweb.org/social_reader"&gt;Indieweb has their own version&lt;/a&gt; of all this, but it’s seriously no joke getting involved. From one of the reader sites, &lt;a href="https://alltogethernow.io/"&gt;Togther&lt;/a&gt;:&lt;/p&gt;



&lt;blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"&gt;
&lt;p class="wp-block-paragraph"&gt;What You Need&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;#1 Your own website&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;On the IndieWeb your website is your identity. It doesn’t need to be advanced, it doesn’t need to be pretty, it just needs to be &lt;strong&gt;yours&lt;/strong&gt;.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;#2 IndieAuth&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;&lt;a href="https://indieweb.org/indieauth"&gt;IndieAuth&lt;/a&gt; is a technology to allow you to sign into services using only your website.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;#3 A MicroSub Server&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;&lt;a href="https://indieweb.org/microsub"&gt;MicroSub&lt;/a&gt; is where the real magic happens. There are 2 parts; the server and the client. Together is the client, but it needs a server to go along with it. The server does a lot of tricky work such as fetching &amp;amp; parsing feeds as well as keeping track of what you have read and how you have everything organized. If you don’t already have a MicroSub server then check out &lt;a href="https://aperture.p3k.io/"&gt;Aperture&lt;/a&gt;.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;#4 MicroPub (optional)&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;&lt;a href="https://indieweb.org/micropub"&gt;MicroPub&lt;/a&gt; is an optional but very cool piece of the puzzle. If your own website has MicroPub functionality then you can use Together not just to read content, but also to reply and create your own content. You can like, repost and reply to stuff you are following, you can even write full on blog posts from inside Together.&lt;/p&gt;
&lt;/blockquote&gt;



&lt;p class="wp-block-paragraph"&gt;I mean, I’m not above some nerd hackin’, but this is 100% not ever going to be a place with a critical mass of my friends just chillin’ and sharing/commenting on blog posts. Way too hard.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;The closest thing I’ve seen is &lt;a href="https://www.commonrss.com/"&gt;CommonRSS&lt;/a&gt; by Brad Coffield which was build in a direct response to my original Bluesky post.&lt;/p&gt;



&lt;figure class="wp-block-embed is-type-rich is-provider-bluesky-social wp-block-embed-bluesky-social"&gt;&lt;/figure&gt;&lt;p class="wp-block-paragraph"&gt;I originally had a gut reaction to the vibe coding nature of it. Like &lt;em&gt;I don’t wanna use this thing you slopped together over a weekend, you gotta get more serious about it first.&lt;/em&gt; Which I admit is just a gut reaction and not a fair assessment of the software. &lt;a href="https://bsky.app/profile/studio303.bsky.social/post/3mhsvtzd5mk2r"&gt;Brad does seem quite sincere&lt;/a&gt; about making it a thing. But at the same time, it feels like it’s been months without updates, which is a bad sign for &lt;em&gt;super brand new&lt;/em&gt; software.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;In testing it lately…&lt;/p&gt;



&lt;ul class="wp-block-list"&gt;&lt;li&gt;It looks great, love the design — but it feels quite slow across the board.&lt;/li&gt;



&lt;li&gt;The Feedbin sync (yay!) didn’t work at first, but appears to be working now.&lt;/li&gt;



&lt;li&gt;It now claims to have 2-way syncing (yay!) but that doesn’t work for me. The articles I read aren’t read in feedbin. The stars don’t sync.&lt;/li&gt;



&lt;li&gt;It’s got the cold-start social problem: there isn’t anyone to follow. The discover page only lists Brad, and clicking the follow button from him doesn’t work.&lt;/li&gt;
&lt;/ul&gt;&lt;p class="wp-block-paragraph"&gt;It feels like it’s close, but it needs to work better. The commenting feature (again, like my main thing for wanting this) requires you to highlight some of the post first, then you can comment, but the comment won’t save. &lt;/p&gt;



&lt;figure class="wp-block-image size-full is-resized"&gt;&lt;img src="https://i0.wp.com/chriscoyier.net/wp-content/uploads/2026/06/Screenshot-2026-06-01-at-8.06.26-AM.png?resize=666%2C678&amp;amp;ssl=1" alt="Screenshot of a user interface with a text box for notes, showcasing a message about a group walk and an error related to JSON input." class="wp-image-13628"&gt;&lt;/figure&gt;&lt;p class="wp-block-paragraph"&gt;CommonRSS feels like a solid concept, but it’s both got the cold-start thing in terms of the social network, but also the cold-start thing in terms of a business. My guess is it’s hard for Brad to muster a ton of enthusiasm to work on the project all day every day with low users. &lt;/p&gt;



&lt;hr class="wp-block-separator has-alpha-channel-opacity"&gt;&lt;p class="wp-block-paragraph"&gt;I’m thinking the main problem is that there just isn’t much of a business to be built around RSS. It can build boutique one-person companies with a passion for it, but even then, difficult. &lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;On top of that, maybe there just isn’t much appetite for the social part? There are a number of arguably already-decently-successful boutique RSS apps, so why haven’t they done it? Why hasn’t Feedbin done anything terribly social? Why not Feedly? Remember FlipBoard’s kind weird taking on RSS? Now they have &lt;a href="https://about.surf.social/"&gt;an equally weird spinoff&lt;/a&gt;. My guess is it’s just too hard of work for too little payoff.&lt;/p&gt;

      &lt;/div&gt;

      
    &lt;/div&gt;&lt;/div&gt;&lt;/body&gt;&lt;/html&gt;</content>
        <author>
            <name/>
        </author>
        <media:content medium="image" url="https://jetpack.com/redirect/?source=sigenerate&amp;query=t%3DeyJpbWciOiJodHRwczpcL1wvY2hyaXNjb3lpZXIubmV0XC93cC1jb250ZW50XC91cGxvYWRzXC8yMDI2XC8wNlwvcGV4ZWxzLXBob3RvLTM3MDAyNTAtMTAyNHg2ODIuanBlZyIsInR4dCI6IlNvY2lhbCBSU1MgKD8pIiwidGVtcGxhdGUiOiJmdWxsc2NyZWVuIiwiZm9udCI6IiIsImJsb2dfaWQiOjc0MDc0MjQ4fQ.WOLKCjcfUYr5xMP44ix1Q1xnFK06KcqYxXL96613SoUMQ"/>
        <source>
            <id>tag:feedly.com,2013:cloud/feed/https://chriscoyier.net/feed/</id>
            <title type="html">Chris Coyier</title>
            <link href="https://chriscoyier.net" rel="alternate" type="text/html"/>
            <updated>2026-06-01T15:42:03Z</updated>
        </source>
    </entry>
    <entry>
        <id>tag:feedly.com,2013:cloud/entry/cOXRjoksGIQzU1pdqbdybn+OTWYeI0riptNneGckdsI=_19e744060dd:50c55:c9e040d5</id>
        <title type="html">On wintering.</title>
        <published>2026-05-29T15:00:36Z</published>
        <updated>2026-05-29T15:00:42Z</updated>
        <link href="https://www.joanwestenberg.com/on-wintering/" rel="alternate" type="text/html"/>
        <summary type="html">The winterer is out of the loop; they're not maintaining a position because they don't have a position to maintain. They can do work that takes longer than a quarter, longer than a year, longer than 5 years, because nobody is auditing the line item.</summary>
        <content type="html">&lt;!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"&gt;
&lt;html&gt;&lt;body&gt;&lt;div&gt;&lt;div&gt;&lt;section&gt;&lt;p&gt;Abraham Lincoln rode home from Washington in December 1849, with what looked like the end of his career packed into his luggage. He'd served one term in the House, alienated his constituents by opposing the Mexican War, and lost his shot at a federal Land Office appointment.&lt;/p&gt;&lt;p&gt;He went back to Springfield to practice law, a near-broken man. And, for nearly 5 years, he barely participated in national politics.&lt;/p&gt;&lt;p&gt;He rode the Illinois circuit, argued patent disputes, and taught himself geometry from Euclid by candlelight in coach inns. He read newspapers obsessively; he read Shakespeare and the King James Bible until he could quote either from pretty much any starting point.&lt;/p&gt;&lt;p&gt;The folks who saw him in those years said he looked...tired.&lt;/p&gt;&lt;p&gt;When he returned to the spotlight, in October 1854, the Kansas-Nebraska Act had cracked the country open. Lincoln walked onto the stage at Peoria and spoke for 3 hours straight. The man who'd been a country lawyer that morning was a national figure by midnight.&lt;/p&gt;&lt;p&gt;Six years later, he was president. &lt;/p&gt;&lt;p&gt;Lincoln's lost years are the part of the biography American children skip past in school; they get the rail-splitter, the beard, the debates, the war, the emancipation, the address, the assassination.&lt;/p&gt;&lt;p&gt;But the 5 years we skip over are the whole ballgame. &lt;/p&gt;&lt;p&gt;They rebuilt the instrument.&lt;/p&gt;&lt;p&gt;The English writer Katherine May coined the modern usage in her 2020 book &lt;em&gt;Wintering&lt;/em&gt;, but the idea is older than the word. Russian peasants called the long quiet stretches between harvests &lt;em&gt;zima&lt;/em&gt; and treated them as a season for weaving, sleeping, repairing tools, and telling stories. Japanese Buddhist monasteries built whole liturgies around rohatsu sesshin, the seven-day winter retreat that closes the year. Foragers like the !Kung and the Hadza, spent something like 4 hours a day on subsistence and the rest on…rest.&lt;/p&gt;&lt;p&gt;Productivity is a recent invention; wintering is not.&lt;/p&gt;&lt;p&gt;Cormac McCarthy published &lt;em&gt;Blood Meridian&lt;/em&gt; in 1985 to a shrugging response. The New York Times reviewed it in a single column. He'd been writing in El Paso for years, broke and largely forgotten. Friends thought he'd peaked. Then in 1992 &lt;em&gt;All the Pretty Horses&lt;/em&gt; came out, won the National Book Award, sold half a million copies, and the back catalog got reissued. McCarthy hadn't been recovering. He'd been finishing something the culture wasn't ready for in 1985 and was ready for by 1992.&lt;/p&gt;&lt;p&gt;He'd been wintering.&lt;/p&gt;&lt;p&gt;Daniel Day-Lewis stopped acting in 1997 and apprenticed as a cobbler in Florence. He came back, played Bill the Butcher in &lt;em&gt;Gangs of New York&lt;/em&gt;, and won an Oscar. He stopped again. Came back. Won another Oscar. Stopped again, and by all reports has actually stopped this time, though I wouldn't bet on it. The cobbler years were how he reset the instrument.&lt;/p&gt;&lt;p&gt;In the long winter, organisms route metabolism inward.&lt;/p&gt;&lt;p&gt;Trees pull resources out of leaves, drop the leaves, and push the sugars down into root systems. Bears don't sleep, exactly. Their core temperature drops a few degrees, their metabolism halves, and they cycle slowly through fat reserves while their kidneys learn to recycle urea into protein. They come out in spring with their bones still mineralized and their muscles roughly intact, which is something no human has yet figured out how to do. What the bear performs is one of the most metabolically sophisticated tricks in the animal kingdom.&lt;/p&gt;&lt;p&gt;The Romans understood that a field left fallow for a season produced more in the next cycle than one worked continuously. Norfolk farmers in the 18th century made it a four-course rotation: wheat, turnips, barley, clover, with the clover restoring nitrogen the wheat had pulled out. The land that looks unused is doing the most useful work.&lt;/p&gt;&lt;p&gt;People who winter well are doing something analogous. They route attention inward and downward, into the parts of the system that don't show up on the surface. They read, they revise, they take long walks they can't account for, and they think the same thought 400 times until it cracks.&lt;/p&gt;&lt;p&gt;Most of what gets published, shipped, posted, and announced is washed off the rocks within a quarter. The people doing it are running on a treadmill that resets their position to zero every Monday. They have to keep producing to stay visible, and visibility is how they earn the right to keep producing.&lt;/p&gt;&lt;p&gt;It's a closed loop, and it generates very little compound interest.&lt;/p&gt;&lt;p&gt;The winterer is off the loop. They aren't maintaining a position because they don't have a position to maintain.&lt;/p&gt;&lt;p&gt;In the short term, you pay dearly for it.&lt;/p&gt;&lt;p&gt;People forget you exist. Calls dry up. Old collaborators stop replying. Younger versions of you lap you in the standings.&lt;/p&gt;&lt;p&gt;The benefit is that you can do work that takes longer than a quarter, and longer than a year, and longer than 5 years, because nobody is auditing the line item.&lt;/p&gt;&lt;p&gt;Charles Darwin came back from the &lt;em&gt;Beagle&lt;/em&gt; voyage in 1836 with the rough outline of natural selection in his head. He published &lt;em&gt;On the Origin of Species&lt;/em&gt; in 1859. The intervening 23 years included long stretches when he wrote almost nothing in his theory notebooks, partly because he was sick, partly because he was writing 8 volumes about barnacles, and partly because he understood the case had to be airtight. When he finally published, the argument was so heavily fortified that the church spent the next 50 years trying to find a hairline crack and failing.&lt;/p&gt;&lt;p&gt;If Darwin had published in 1840, he might be a footnote. His 23 years of comparative silence were the moat.&lt;/p&gt;&lt;p&gt;Robert Caro started his Lyndon Johnson biography in 1976. He's published 4 volumes of an intended 5. He's now 90. He moved to the Texas Hill Country to live among the people Johnson grew up with, because he thought he couldn't write about a man without inhabiting his weather. Each volume took roughly a decade. The publishing world treats him as a slow eccentric. Anyone who's read the books knows he's running a different clock, on a different scale, and that no one currently working at speed is going to produce anything close.&lt;/p&gt;&lt;p&gt;Plenty of people stop and produce nothing. The graveyard of failed comebacks is large, and wintering is dangerous as a strategy because most attempts at it collapse into actual stagnation.&lt;/p&gt;&lt;p&gt;The difference between the two is invisible from the outside, until the end.&lt;/p&gt;&lt;p&gt;The reason the wintering few register as dangerous, when they re-emerge, is that they have something the still-busy don't have: a center of gravity. They've spent enough time alone with a single problem to develop actual opinions about it, opinions that don't move when other people push on them. In a culture optimized for constant repositioning, conviction is a structural advantage. The market doesn't know how to price it.&lt;/p&gt;&lt;p&gt;The winterer has been watching while you weren't looking. They've watched the consensus shift, watched the mistakes pile up. When they come back, they come back with reads you can't get from inside the swirl, because the swirl makes you stupid.&lt;/p&gt;&lt;p&gt;The philosopher Hannah Arendt, writing in &lt;em&gt;The Life of the Mind&lt;/em&gt; in the 1970s, described thinking itself as a form of withdrawal. You can't think and act at the same time, she said, because thinking pulls you out of the stream of ongoing events. She was suspicious of people who claimed to do both at once.&lt;/p&gt;&lt;p&gt;The British psychiatrist Anthony Storr, in &lt;em&gt;Solitude&lt;/em&gt; (1988), made the case that the most original work of major figures often came out of long isolated stretches. Newton in plague-year Cambridge. Wittgenstein in Norway. Kafka in Zürau. Beckett in his Paris apartment with the curtains drawn. Storr wasn't romanticizing it; the isolated stretches were often miserable, sometimes pathological. But the work that came out of them had a density that wasn't available to people doing it part-time.&lt;/p&gt;&lt;p&gt;Any culture that systematically punishes withdrawal is going to lose its most concentrated thinkers to either burnout or invisibility. The modern knowledge economy, with its ambient pressure to post, ship, and stay in the conversation, is a machine for producing exactly that loss. The people we'll wish we had in 15 years are, right now, being shamed into producing slop they don't believe in, because the alternative is to drop out, and dropping out reads as failure.&lt;/p&gt;&lt;p&gt;The winterers who survive this will be those who can tolerate looking like they failed. This is a real and rare psychological skill, and most people don't have it. It requires you to be okay with the wrong kind of silence around your name for years. It requires you to pass on small wins that would re-establish your position. It requires you to bet that what you're working on is worth more than what you're giving up, when the only person who can evaluate the bet is you, and you might be wrong, and you'll only know in 7 years.&lt;/p&gt;&lt;p&gt;Lincoln didn't know in 1851 that he was wintering.&lt;/p&gt;&lt;p&gt;He thought he was finished.&lt;/p&gt;&lt;p&gt;He told his law partner William Herndon that his political career was over, and he believed it. And then his country produced an emergency that demanded exactly the kind of mind he'd been nurturing, and he was the man of the hour whose hour had finally come.&lt;/p&gt;&lt;p&gt;The people who appear to have stopped, in any given year, are mostly people who have actually stopped. But small fraction of them are doing the other thing. &lt;/p&gt;&lt;p&gt;Our world produces emergencies on a reliable schedule; when the next one comes, watch who walks out of the woods.&lt;/p&gt;
  &lt;/section&gt;&lt;/div&gt;&lt;/div&gt;&lt;/body&gt;&lt;/html&gt;</content>
        <author>
            <name/>
        </author>
        <media:content medium="image" url="https://www.joanwestenberg.com/content/images/size/w1200/2026/04/lincoln-1863-gettyimages-177602038-1377722101.jpg"/>
        <source>
            <id>tag:feedly.com,2013:cloud/feed/https://www.joanwestenberg.com/rss/</id>
            <title type="html">Westenberg.</title>
            <link href="https://www.joanwestenberg.com" rel="alternate" type="text/html"/>
            <updated>2026-05-29T15:00:42Z</updated>
        </source>
    </entry>
    <entry>
        <id>tag:feedly.com,2013:cloud/entry/cOXRjoksGIQzU1pdqbdybn+OTWYeI0riptNneGckdsI=_19e4e658f88:2824bd:1d3b9ec4</id>
        <title type="html">10x engineers: the Purple Developer</title>
        <published>2026-05-22T06:35:39Z</published>
        <updated>2026-05-22T06:35:45Z</updated>
        <link href="https://jessitron.com/2020/12/26/purple-developer/" rel="alternate" type="text/html"/>
        <summary type="html">One way to be a 10x developer is to write the system, so you know more about it that anyone else. I call this person the “purple developer.”</summary>
        <content type="html">&lt;!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"&gt;
&lt;html&gt;&lt;body&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;
			
&lt;p class="wp-block-paragraph"&gt;What makes a software engineer productive? You can list attributes like experience with the language, scientific mindset, intelligence, focus, a personally crafted IDE setup. Yet, in my experience, far and away the biggest factor is: familiarity with the codebase they’re changing.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;That knowledge of what the system does and needs to do, it’s completely essential and entirely contextual. The easiest way to get is to create it — that is, to write that software from scratch. And then it feels completely natural. It doesn’t feel like knowledge, it feels like breathing. It feels obvious.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;When you have a decent mental model of a system, sharing that with others is hard. You don’t know how much you know. If you’re the purple developer in this picture:&lt;/p&gt;



&lt;figure class="wp-block-image"&gt;&lt;img src="https://i1.wp.com/jessitron.com/wp-content/uploads/2018/04/4e765-1fneesy_bw-arepj9j6adsa.png?w=840&amp;amp;ssl=1" alt=""&gt;&lt;figcaption&gt;below the line, a software system; above it, a purple person with a mental model of the system. A blue person and a green person with very incomplete models and lots of questions.&lt;/figcaption&gt;&lt;/figure&gt;&lt;p class="wp-block-paragraph"&gt;then you have a mental model of this system because you built it. The green and blue developers have been assigned to help, but they can’t change the system because they don’t understand it. Meanwhile, you may be changing the system fast enough that it’s impossible for them to get a grasp on it, no matter how smart they are. (I’ve been in their situation.) The solution is to work &lt;em&gt;together&lt;/em&gt; on the system, and invest attention in transferring your mental model. Until then, Blue and Green get in your way.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;This slide is part of my &lt;a href="https://jessitron.com/camerata"&gt;Collective Problem Solving&lt;/a&gt; keynote (also seen as Origins of Opera). People came up to me afterward: “We have a purple developer. Now I don’t feel so bad about being blue or green” or “Oh no, I’m the purple developer!” &lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Which developer in this picture is ten times more productive than the others? Purple developer!&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Is it because they are inherently smarter? Nah. Circumstances lead to this situation.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;There is not any “productive” software engineer so much as “productive in this codebase.” &lt;a href="https://jessitron.com/2017/06/24/the-most-productive-circumstances-for/"&gt;Spread the knowledge, spread the productivity.&lt;/a&gt;&lt;/p&gt;
		&lt;/div&gt;

					
			&lt;/div&gt;&lt;/div&gt;&lt;/body&gt;&lt;/html&gt;</content>
        <author>
            <name>jessitron</name>
        </author>
        <media:content medium="image" url="https://i0.wp.com/jessitron.com/wp-content/uploads/2019/05/cropped-cropped-logo-by-linda-2.png?fit=240%2C240&amp;ssl=1"/>
        <link href="https://s0.wp.com/_si/?t=eyJpbWciOiJodHRwczpcL1wvaTAud3AuY29tXC9qZXNzaXRyb24uY29tXC93cC1jb250ZW50XC91cGxvYWRzXC8yMDE5XC8wNVwvY3JvcHBlZC1jcm9wcGVkLWxvZ28tYnktbGluZGEtMi5wbmc_Zml0PTUxMiUyQzUxMiZzc2w9MSIsInR4dCI6Ikplc3NpdHJvbiIsInRlbXBsYXRlIjoiZWRnZSIsImZvbnQiOiIiLCJibG9nX2lkIjoxNjIzNTk4MzZ9.H4uKTfuoWCLiBn0JsgmqYGglAJIdwtAJ-del4_sSPNcMQ" rel="enclosure" type="image"/>
        <source>
            <id>tag:feedly.com,2013:cloud/feed/https://jessitron.com/feed/</id>
            <title type="html">Jessitron</title>
            <link href="https://jessitron.com" rel="alternate" type="text/html"/>
            <updated>2026-05-22T06:35:45Z</updated>
        </source>
    </entry>
    <entry>
        <id>tag:feedly.com,2013:cloud/entry/cOXRjoksGIQzU1pdqbdybn+OTWYeI0riptNneGckdsI=_19e2a09a0f2:5db05a:10dfc124</id>
        <title type="html">Native Apps Should Be Avoided Whenever Possible</title>
        <published>2026-05-15T05:08:54Z</published>
        <updated>2026-05-15T05:08:58Z</updated>
        <link href="https://nooneshappy.com/article/native-apps-should-be-avoided-whenever-possible/" rel="alternate" type="text/html"/>
        <summary type="html">Why native apps have become privacy liabilities, and why the browser is almost always the better choice.</summary>
        <content type="html">&lt;!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"&gt;
&lt;html&gt;&lt;body&gt;&lt;div&gt;&lt;div&gt; &lt;article&gt;&lt;header&gt;&lt;time datetime="2026-04-12"&gt;April 12, 2026&lt;/time&gt;&lt;h1&gt;Native Apps Should Be Avoided Whenever Possible&lt;/h1&gt; &lt;/header&gt;&lt;blockquote&gt;
&lt;p&gt;TL;DR: &lt;strong&gt;What you should do:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;Openly refuse apps, and vocally advocate for the web instead.&lt;/li&gt;
&lt;li&gt;Try not to install any apps if you don’t need to.&lt;/li&gt;
&lt;li&gt;If a service has a functioning website, use it instead.&lt;/li&gt;
&lt;li&gt;Revoke all permissions by default, including background location, microphone, and camera permissions for anything that doesn’t require them to function.&lt;/li&gt;
&lt;li&gt;Audit your installed apps. Uninstall all apps you don’t actively need.&lt;/li&gt;
&lt;li&gt;Treat every “download our app” prompt with skepticism.&lt;/li&gt;
&lt;/ul&gt;&lt;/blockquote&gt;
&lt;p&gt;Most native apps collect far more data than their website equivalents ever could. They request permissions to hardware, sensors, and background processes that browsers deliberately restrict. The third-party software embedded in these apps frequently transmits your location, device identifiers, and behavioral data to third parties before you even see a consent prompt. This data is in tandem bought, sold, and aggregated by brokers. It has been used to out individuals, track immigrants, and enable prosecution over reproductive healthcare.&lt;/p&gt;
&lt;h2 id="the-white-house-app"&gt;The White House App&lt;/h2&gt;
&lt;p&gt;On March 27, 2026, the Trump administration released an official White House app for iOS and Android. Within hours, two independent security researchers decompiled it and published their findings [&lt;a href="https://nooneshappy.com/article/native-apps-should-be-avoided-whenever-possible/#ref-1"&gt;1&lt;/a&gt;]. The app is a textbook example of everything wrong with the native app model.&lt;/p&gt;
&lt;p&gt;Apple requires apps to submit a privacy manifest disclosing what data they collect. The White House app declared an empty array. Zero data collection. Meanwhile, the actual binary contained ten analytics frameworks, including the full OneSignal SDK with a sub-framework specifically for location tracking [&lt;a href="https://nooneshappy.com/article/native-apps-should-be-avoided-whenever-possible/#ref-2"&gt;2&lt;/a&gt;]. The GPS pipeline polled precise coordinates every 4.5 minutes in the foreground and every 9.5 minutes in the background, syncing everything to OneSignal’s commercial servers. A boolean flag in OneSignal’s server responses could remotely enable or disable GPS tracking without an app update and without Apple review.&lt;/p&gt;
&lt;p&gt;An Exodus Privacy audit identified three embedded trackers, one of which was Huawei Mobile Services Core [&lt;a href="https://nooneshappy.com/article/native-apps-should-be-avoided-whenever-possible/#ref-3"&gt;3&lt;/a&gt;]. The app’s privacy policy, last updated January 20, 2025, makes no mention of GPS tracking, OneSignal, or background data collection.&lt;/p&gt;
&lt;p&gt;Nearly everything in the app is available on whitehouse.gov. The app’s unique additions are push notifications, a pre-filled text message to the President, and an ICE tip button (also available on ice.gov). What it actually added at scale was a surveillance pipeline: 77% of the app’s network requests go to third parties, not whitehouse.gov.&lt;/p&gt;
&lt;h2 id="the-software-embedded-in-apps"&gt;The Software Embedded in Apps&lt;/h2&gt;
&lt;p&gt;Most people think of apps as products built by a single company. In practice, the average app is a thin wrapper around dozens of third-party software packages, each with its own data collection pipeline and commercial incentives. When you grant an app permission to access your location, every package embedded in that app inherits that permission. A single package can appear in hundreds of apps, feeding location data on millions of people to a single aggregator.&lt;/p&gt;
&lt;p&gt;In January 2025, a hacker breached Gravy Analytics and leaked roughly 30 million location records collected from 3,455 apps — dating, fitness, gaming, and health apps among them [&lt;a href="https://nooneshappy.com/article/native-apps-should-be-avoided-whenever-possible/#ref-4"&gt;4&lt;/a&gt;]. The FTC subsequently banned Gravy Analytics from selling Americans’ location data [&lt;a href="https://nooneshappy.com/article/native-apps-should-be-avoided-whenever-possible/#ref-5"&gt;5&lt;/a&gt;], but by then the data was already circulating on cybercrime forums.&lt;/p&gt;
&lt;p&gt;In a separate case, Google paid $391.5 million to settle claims from 40 states for continuing to collect location data even when users explicitly disabled location tracking [&lt;a href="https://nooneshappy.com/article/native-apps-should-be-avoided-whenever-possible/#ref-6"&gt;6&lt;/a&gt;].&lt;/p&gt;
&lt;h2 id="why-everyone-should-care"&gt;Why Everyone Should Care&lt;/h2&gt;
&lt;p&gt;This data is bought, sold, and aggregated by brokers. It has been used to out individuals, track immigrants, and enable prosecution over reproductive healthcare. In multiple cases, journalists and private groups have purchased app-derived location data to identify specific people based on their movements.&lt;/p&gt;
&lt;p&gt;There are virtually no restrictions in the United States on buying, selling, or weaponizing this data. There is no comprehensive federal privacy law. And there isn’t likely to be one soon. The best we can do is minimize the data we share in the first place.&lt;/p&gt;
&lt;h2 id="what-apps-can-do-that-websites-cant"&gt;What Apps Can Do That Websites Can’t&lt;/h2&gt;
&lt;p&gt;The core argument for using the website instead of the app comes down to what each platform is technically capable of doing without your knowledge.&lt;/p&gt;

































































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Capability&lt;/th&gt;&lt;th&gt;Native App&lt;/th&gt;&lt;th&gt;Website / PWA&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Background location tracking&lt;/td&gt;&lt;td&gt;Yes, can poll GPS continuously&lt;/td&gt;&lt;td&gt;No&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Run at device startup&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;&lt;td&gt;No&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Access biometric hardware&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;&lt;td&gt;Limited (WebAuthn, user initiated)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Modify or delete device storage&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;&lt;td&gt;No (sandboxed to browser)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Embed invisible third-party software&lt;/td&gt;&lt;td&gt;Yes, all inherit granted permissions&lt;/td&gt;&lt;td&gt;No, scripts visible in page source&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Transmit data before consent prompt&lt;/td&gt;&lt;td&gt;Yes (common with third-party software)&lt;/td&gt;&lt;td&gt;Restricted by browser policies&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Push notifications while closed&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;&lt;td&gt;Yes (PWA, user opt in required)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Access contacts, call logs, SMS&lt;/td&gt;&lt;td&gt;Yes (if permitted)&lt;/td&gt;&lt;td&gt;No&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Prevent phone from sleeping&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;&lt;td&gt;No&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Camera and microphone&lt;/td&gt;&lt;td&gt;Yes (persistent if granted)&lt;/td&gt;&lt;td&gt;Yes (per session, prompted each time)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Offline functionality&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;&lt;td&gt;Yes (via service workers)&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;The browser is the security boundary. Websites operate within it. Native apps bypass it.&lt;/p&gt;
&lt;h2 id="the-access-provided-by-default-is-enough-to-do-real-harm"&gt;The Access Provided by Default is Enough to Do Real Harm&lt;/h2&gt;
&lt;p&gt;The moment you install an app, before you allow a single permission prompt, it can:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;Reach any server on the internet&lt;/li&gt;
&lt;li&gt;Read your IP address, device model, OS version, timezone, country, carrier, and network type&lt;/li&gt;
&lt;li&gt;Generate and persist a unique identifier tied to your device&lt;/li&gt;
&lt;li&gt;Run code at device startup (Android) and wake up in the background&lt;/li&gt;
&lt;li&gt;Fingerprint your device by combining the above into a signature that follows you across sessions&lt;/li&gt;
&lt;li&gt;Grant all of this same access to every third-party software package embedded in the app&lt;/li&gt;
&lt;li&gt;Compare this data to other datasets to infer your identity, demographics, interests, and habits&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;The runtime permission prompts you actually see (location, camera, contacts) are helpful while annoying, but the majority of the default access permissions do not require your consent.&lt;/p&gt;
&lt;p&gt;A website, by contrast, starts with almost none of this: no persistent identifier, no background execution, no third-party software inheritance, no startup hooks.&lt;/p&gt;
&lt;h2 id="some-things-need-to-be-apps-but-most-dont"&gt;Some Things Need to Be Apps, But Most Don’t&lt;/h2&gt;
&lt;p&gt;Some things need to be apps. AR and VR, real-time games, anything talking to NFC or Bluetooth hardware, serious audio and video work, accessibility tools. These are legitimate cases where the browser sandbox is the limitation. In these circumtances, I personally use a full computer as opposed to my phone.&lt;/p&gt;
&lt;p&gt;Almost nothing else qualifies. Your banking, your travel, your grocery store, the restaurant down the street — none of it needs an app. And rewards be damned. No rewards are worth the data you are willingly giving them.&lt;/p&gt;
&lt;p&gt;Same goes for hardware. If a thermostat or a fitness tracker can’t be set up without a proprietary app, that’s a flaw in the product, not a feature. I immediately avoid such products. You’re buying an ongoing relationship with someone else’s servers and guaranteeing that you’ll forget that corporations are watching everything they can.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I avoid most apps. It turns out this is easier than most people assume, because the app is almost never the only option. It is just the option the company wants you to take and not enough people question.&lt;/p&gt;
&lt;p&gt;We are at a very specific time in humanity right now. Where aggregating data is a currency, and it is actively being utilized at a scale never before seen. I recommend you at least take stock of what you’re freely giving away.&lt;/p&gt;
&lt;hr&gt;&lt;h2 id="references"&gt;References&lt;/h2&gt;
&lt;p&gt;&lt;span id="ref-1"&gt;1.&lt;/span&gt; &lt;a href="https://thereallo.dev/blog/decompiling-the-white-house-app"&gt;I Decompiled the White House’s New App&lt;/a&gt; (Thereallo, March 28, 2026) and &lt;a href="https://www.atomic.computer/blog/white-house-app-security-analysis/"&gt;Security Analysis of the Official White House iOS App&lt;/a&gt; (atomic.computer, March 27, 2026). Two independent researchers decompiled the app on Android and iOS within hours of release.&lt;/p&gt;
&lt;p&gt;&lt;span id="ref-2"&gt;2.&lt;/span&gt; &lt;a href="https://www.atomic.computer/blog/white-house-app-security-analysis/"&gt;Security Analysis of the Official White House iOS App&lt;/a&gt; (atomic.computer). Documents the empty privacy manifest, OneSignal SDK with ten sub-frameworks, and the remote GPS toggle via server response.&lt;/p&gt;
&lt;p&gt;&lt;span id="ref-3"&gt;3.&lt;/span&gt; &lt;a href="https://reports.exodus-privacy.eu.org/en/reports/gov.whitehouse.app/latest/"&gt;Exodus Privacy Report: gov.whitehouse.app&lt;/a&gt;. Automated audit identifying three embedded trackers including Huawei Mobile Services Core. Additional context in &lt;a href="https://www.sambent.com/the-white-house-app-has-huawei-spyware-and-an-ice-tip-line/"&gt;Fedware: 13 Government Apps That Spy Harder Than the Apps They Ban&lt;/a&gt; (Sam Bent).&lt;/p&gt;
&lt;p&gt;&lt;span id="ref-4"&gt;4.&lt;/span&gt; &lt;a href="https://techcrunch.com/2025/01/13/gravy-analytics-data-broker-breach-trove-of-location-data-threatens-privacy-millions/"&gt;A breach of Gravy Analytics’ huge trove of location data threatens the privacy of millions&lt;/a&gt; (TechCrunch, January 13, 2025).&lt;/p&gt;
&lt;p&gt;&lt;span id="ref-5"&gt;5.&lt;/span&gt; &lt;a href="https://www.ftc.gov/news-events/news/press-releases/2025/01/ftc-finalizes-order-prohibiting-gravy-analytics-venntel-selling-sensitive-location-data"&gt;FTC Finalizes Order Prohibiting Gravy Analytics, Venntel from Selling Sensitive Location Data&lt;/a&gt; (FTC, January 14, 2025).&lt;/p&gt;
&lt;p&gt;&lt;span id="ref-6"&gt;6.&lt;/span&gt; &lt;a href="https://techcrunch.com/2022/11/14/google-pay-391-5-million-location-tracking-settlement/"&gt;Google to pay $391.5 million in location tracking settlement with 40 states&lt;/a&gt; (TechCrunch, November 14, 2022).&lt;/p&gt;  &lt;/article&gt;&lt;/div&gt;&lt;/div&gt;&lt;/body&gt;&lt;/html&gt;</content>
        <author>
            <name>No One's Happy</name>
        </author>
        <source>
            <id>tag:feedly.com,2013:cloud/feed/https://nooneshappy.com/rss.xml</id>
            <title type="html">No One's Happy</title>
            <link href="https://nooneshappy.com" rel="alternate" type="text/html"/>
            <updated>2026-05-15T05:08:58Z</updated>
        </source>
    </entry>
    <entry>
        <id>tag:feedly.com,2013:cloud/entry/cOXRjoksGIQzU1pdqbdybn+OTWYeI0riptNneGckdsI=_19e00ecc82e:330034:c12867d</id>
        <title type="html">AI dělá chyby a autisté je dokážou najít. Z jejich jinakosti dělá Češka ve svém startupu přednost</title>
        <published>2026-05-07T05:32:58Z</published>
        <updated>2026-05-07T05:33:01Z</updated>
        <link href="https://cc.cz/ai-dela-chyby-a-autiste-je-dokazou-najit-z-jejich-jinakosti-dela-ceska-ve-svem-startupu-prednost/" rel="alternate" type="text/html"/>
        <summary type="html">„I nejpokročilejší vývojářské týmy musí manuálně odstraňovat duplicity a řešit případy, kde automatizace selhává,“ říká Irena Zatloukalová.</summary>
        <content type="html">&lt;!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"&gt;
&lt;html&gt;&lt;body&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;

					
&lt;p&gt;

	
	

	
	

	
&lt;/p&gt;
&lt;p&gt;Představte si konkrétní situaci: datoví vědci ve startupu trénují svůj analytický model, ale v určitých případech narážejí na vysokou chybovost v podobě falešně pozitivních výsledků. Místo toho, aby se pálil drahý čas seniorních inženýrů na manuálním čištění datasetů, předá se úkol ven. Výsledek? Najatý tým projde pět iterací dat a pomůže tak o polovinu zlepšit úspěšnost modelu. Právě na tom staví mladý pražský startup Diversight. Jeho tajnou zbraní nejsou pokročilejší algoritmy, nýbrž dedikovaní analytici na autistickém spektru. Ukazuje tak, že vlastnosti, kvůli kterým se jiné firmy těmto lidem někdy vyhýbají, se mohou proměnit na silné stránky.&lt;/p&gt;&lt;p id="czech-bbc21e7e4b919b9a9b21266f2b6fc810"&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;„Nejsme charita ani neziskovka, jsme klasická technologická firma,“ &lt;/em&gt;říká hned na úvod spoluzakladatelka a ředitelka Diversightu Irena Zatloukalová. V českém technologickém prostředí se pohybuje dvacet let, a to zejména v oblasti komunikace, kdy sedm let byla mluvčí tuzemské internetové jedničky Seznam.cz. Mimo jiné působila i jako spolumajitelka PR agentury Fenek a později na volné noze radila s komunikací technologickým firmám jako Heureka, Apify, Liftago či Ackee. Loni v červenci ale všechny klienty předala dál a naplno se vrhla do nového byznysu.&lt;/p&gt;
&lt;p&gt;V Diversightu se zaměřuje na takzvaný datový dluh. V éře, kdy se prakticky každá firma snaží do svých procesů implementovat umělou inteligenci, stojí budoucí úspěch primárně na kvalitě vstupních dat. &lt;em&gt;„I ty nejpokročilejší vývojářské týmy totiž musí manuálně odstraňovat duplicity a řešit hraniční případy, v nichž zavedená automatizace zkrátka selhává a modely začínají generovat nesmysly. Diversight funguje jako filtr, který přebírá na přesnost náročnou vrstvu ekosystému a zajišťuje potřebnou lidskou pojistku proti halucinacím,“&lt;/em&gt; vysvětluje pro CzechCrunch Zatloukalová.&lt;/p&gt;


&lt;div&gt;
	&lt;div&gt;&lt;a href="https://cc.cz/ai-dela-chyby-a-autiste-je-dokazou-najit-z-jejich-jinakosti-dela-ceska-ve-svem-startupu-prednost/galerie/541483/"&gt;&lt;span&gt;&lt;img src="https://cc.cz/wp-content/uploads/2026/04/zatloukalova-simon-815x509.jpg" alt="zatloukalova-simon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;p&gt;&lt;span&gt;Foto: Diversight&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;p&gt;Irena Zatloukalová s kolegou Šimonem&lt;/p&gt;&lt;/div&gt;

&lt;p&gt;Právě v oblasti hledání nepatrných vzorců totiž samotná umělá inteligence běžně naráží na své limity, dodává. Pokud modely generují opakující se chyby, vývojářům nepostačí jen jednoduché přepsání textového promptu. Týmy potřebují člověka, který dokáže precizně pochopit byznysovou logiku a vyčíst přímo ze syrové databáze konkrétní pravidla a odchylky. &lt;em&gt;„V tom máme ohromnou výhodu, protože máme lidi, kterým jednou řeknete pravidla a oni pak po nich neúnavně půjdou, od prvního řádku až po řádek číslo 1 500,“&lt;/em&gt; popisuje specifikum práce Zatloukalová.&lt;/p&gt;
&lt;p&gt;Doplňuje přitom, že jejím lidem nedělá problém udržet stejnou hladinu pozornosti na jednom tématu klidně i osm dní v kuse: &lt;em&gt;„Prostě potřebují problém vyřešit, neznámou najít a věc dotáhnout do konce. To pomyšlení &lt;/em&gt;&lt;em&gt;na rozlousknutí problému pomáhá jejich fokusu.“&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Na samotném začátku příběhu Diversightu přitom nestála Zatloukalová. &lt;em&gt;„Ráda bych to říkala, ale bohužel to nebyl můj nápad,“ &lt;/em&gt;usmívá se a jako originálního tvůrce označuje Tomáše Borovičku z technologické společnosti Datamole. Ten na zahraničních trzích narazil na izraelskou firmu Point AI, která budovala data-anotační byznys (zaměřený na označování surových dat) na přesné práci lidí na spektru. Od té doby přemýšlel nad tím, jak vyzkoušet podobný koncept i v Česku.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;„Byla to jedna večeře, jedno potkání, tři hodiny povídání. Šli jsme hodně do hloubky a do našich hodnot a na konci mi řekl: Tak jo, pojďme to zkusit,“&lt;/em&gt; vzpomíná Zatloukalová na zlom, který přišel v prosinci 2024. A dodává, že na začátku je propojila Lenka Kučerová ze spolku prg.ai.&lt;/p&gt;



&lt;p&gt;Původní plán Diversightu počítal s tím, že se do Prahy přenese jako franšíza přímo izraelský model. Rychlý průzkum trhu ale ukázal, že běžný anotační byznys je v tuzemsku v podstatě jen levná komodita, kde firmy často najímají studenty a na finální kvalitě jim tolik nesejde. Zatímco v Izraeli se data pro zdravotnictví či zbrojní průmysl anotují s kritickou přesností, v lokálních podmínkách by takový model ekonomicky nepřežil. Diversight proto musel okamžitě změnit plány. Zaměřil se na komplexnější analytické úkoly a takzvanou validaci s člověkem v procesu (human-in-the-loop), kde se naplno využije kognitivní preciznost ve složitých datech.&lt;/p&gt;
&lt;p&gt;Projekt od začátku strategicky i finančně podpořil zmíněný Datamole, který mu poskytl peníze na bezpečný roční provoz a působí v roli partnera. Mimo jiné nabízí i přímý přístup ke svým seniorním AI architektům. Hlavním byznysovým úkolem pro nadcházející měsíce je tak dostat Diversight do zisku díky příjmům ze zakázek.&lt;/p&gt;


&lt;div&gt;
	&lt;div&gt;&lt;a href="https://cc.cz/ai-dela-chyby-a-autiste-je-dokazou-najit-z-jejich-jinakosti-dela-ceska-ve-svem-startupu-prednost/galerie/541481/"&gt;&lt;span&gt;&lt;img src="https://cc.cz/wp-content/uploads/2026/04/borovicka-zatloukalova-815x509.jpg" alt="borovicka-zatloukalova"&gt;&lt;/span&gt;&lt;/a&gt;&lt;p&gt;&lt;span&gt;Foto: Diversight&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;p&gt;Tomáš Borovička a Irena Zatloukalová&lt;/p&gt;&lt;/div&gt;

&lt;p&gt;Mezi aktuální klienty vedle &lt;a href="https://cc.cz/sbiraji-data-o-kozach-e-shopech-i-teslach-cesky-startup-dela-byznys-na-tom-co-na-sebe-firmy-prozradi/"&gt;analytické společnosti BizMachine,&lt;/a&gt; pro kterou startup dělá v úvodu zmíněné čištění dat, patří například také InfraHex, jedna z firem holdingu Respilon. Ta vyvinula technologii, která upravuje tepelnou stopu živých i neživých objektů a tím omezuje jejich detekci pomocí termokamer. V současnosti se využívá i na Ukrajině, kde pomáhá vojákům v terénu. I drobné odchylky zde hrají zásadní roli, protože se systém opírá o přesné analýzy obrazů v různých infra spektrech. A tak se na této detailní práci vyhodnocování a výběru dat podílejí lidé na autistickém spektru.&lt;/p&gt;
&lt;p&gt;Českým mediálním i firemním prostorem dnes podle Zatloukalové bohužel rezonují převážně extrémní obrazy autismu, kdy na jedné straně stojí příběhy nespolupracujících jedinců s těžkým postižením, na straně druhé zprofanované postavy geniálních vědců, jako je například Sheldon Cooper z &lt;em&gt;Teorie velkého třesku&lt;/em&gt;. Diversight ale systematicky hledá velkou množinu lidí s nadprůměrnou analytickou inteligencí ležící mezi těmito dvěma extrémy. Většina z nich má však potíže projít přes výběrová řízení či běžná HR oddělení, protože standardní firemní postupy zkrátka neumí s neurodiverzitou pracovat.&lt;/p&gt;
&lt;div&gt;&lt;blockquote&gt;Pokud zahodíte své ego a uznáte, že někdo našel lepší cestu, firmě to hodně pomůže.&lt;/blockquote&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;„Už jen to, když do pracovního inzerátu vypíšete deset věcí jako ‚nice to have‘. Člověk na spektru si to projde, u třetí položky si řekne, že má jen dva a půl roku zkušeností místo tří, takže to není práce pro něj, a jde dál,“ &lt;/em&gt;vysvětluje Zatloukalová jeden z mnoha detailů, proč kandidáti sami rovnou z recruitmentu vypadávají. Značná část lidí na spektru tak i kvůli tomu končí na úřadu práce či na podřadných pozicích a ve firmách běžně narazí kvůli logickému poukazování na neefektivitu a navrhování lepších postupů.&lt;/p&gt;
&lt;p&gt;Zatloukalová proto změnila rovnou i náborový proces a přizpůsobila ho lidem na spektru. Přesné zadání úkolů a otázky zasílá s předstihem, kandidáty navíc netestuje pod umělým tlakem, ale zaměřuje se striktně na jejich schopnost strukturovaně přemýšlet. Aktuálně má firma pět lidí – vedle samotné Zatloukalové je to technologický manažer Adam Vesecký a interní tým tří specializovaných analytiků. Záměrem je tým rozšiřovat, nicméně se stropem na hranici deseti zaměstnanců, aby firma nepřišla o klidné prostředí komorního kolektivu.&lt;/p&gt;



&lt;p&gt;Zatloukalová navíc varuje před zjednodušováním nebo předsudky, že práce s neurodivergentními lidmi přináší jen těžkosti a komunikační zádrhele. Na první pohled nepříjemné situace, kdy podřízený manažerovi zcela upřímně oznámí, že zadal úkol špatně, totiž vedou k lepším procesům do budoucna, a tím i výsledkům. &lt;em&gt;„Pokud zahodíte své ego a uznáte, že někdo našel lepší cestu, firmě to hodně pomůže,“ &lt;/em&gt;vysvětluje Zatloukalová.&lt;/p&gt;
&lt;p&gt;Lidé na spektru podle ní přinášejí do byznysu inovace a odlišné úhly pohledu nejen v datové analytice, ale napříč všemi obory od zákaznické podpory po design. &lt;em&gt;„Mají přirozenou schopnost jít striktně po podstatě problému a všímat si i drobných odchylek, které neurotypická většina snadno přehlédne,“ &lt;/em&gt;doplňuje. Výměnou za tento výkon často vyžadují jen velmi specifické, avšak finančně nenáročné úpravy pracovního prostředí – typicky přesun stolu dál od rušné kuchyňky, utlumení ostrého kancelářského osvětlení nebo zkrátka jen možnost po náročné schůzce úplně vypnout a odejít domů.&lt;/p&gt;
&lt;div&gt;&lt;blockquote&gt;Cítím nespravedlnost. Jsem naštvaná na to, jakým způsobem se společnost staví k lidem, kteří jsou jiní.&lt;/blockquote&gt;&lt;/div&gt;
&lt;p&gt;Častou chybou některých manažerů je tyto potřeby zpochybňovat jen proto, že zaměstnanec nemá na stole oficiální lékařskou diagnózu. &lt;em&gt;„Moje velká prosba k jakémukoliv manažerovi je: i bez diagnózy člověka poslouchejte. Když říká, že něco potřebuje, respektujte to, nezpochybňujte a hledejte cesty, jak zařídit, aby mohl svoji práci vykonávat co nejlépe,“&lt;/em&gt; apeluje. Jak sama upozorňuje, nevyžaduje to stavbu drahých oddělených kanceláří, často stačí investice do kvalitních sluchátek s aktivním potlačením hluku.&lt;/p&gt;
&lt;p&gt;Přístup orientovaný na lidi se specifickými potřebami má podle Zatloukalové přesah do celkového chodu jakékoliv firmy. Veškerá drobná provozní pravidla a limity, které startup explicitně zavádí kvůli neurodivergentním kolegům, totiž v důsledku ulehčují práci všem. &lt;em&gt;„Každý zaměstnanec občas potřebuje ničím nerušený čas na práci, jen se to v běžných korporacích tolik neakcentuje. Funguje zde stejný princip jako v moderním urbanismu. Pokud navrhnete veřejný prostor tak, aby vyhovoval lidem na vozíku, dětem i rodičům s kočárky, vytvoříte ve finále vysoce funkční prostředí, ve kterém se bude dobře žít úplně všem,“ &lt;/em&gt;srovnává.&lt;/p&gt;
&lt;p&gt;Na druhou stranu Zatloukalová doplňuje, že budování neurodiverzního týmu s sebou pro vedení nese nutnost preciznosti v mezilidské komunikaci. &lt;em&gt;„Tou se živím dvacet let a největší paradox je, že se mi opravdu stává, že si s kolegy nerozumím v zadání,“&lt;/em&gt; přiznává s tím, že sama musela odložit své ego stranou a opět se učit zadávat úkoly maximálně jasně, doslovně a bez zbytečného sarkasmu.&lt;/p&gt;
&lt;p id="czech-7d2b87ee68a47d335feeceb6c53fb9c5"&gt;&lt;/p&gt;&lt;p id="czech-e70ae63f514d21e002eeddcd6c33af7a"&gt;&lt;/p&gt;&lt;p&gt;To vše se promítá i do samotného workflow při řešení úkolů pro klienty. &lt;em&gt;„Když řeknu ‚udělej A‘, kolega si začne domýšlet B, C a D. A místo toho, aby se zeptal, radši to rovnou udělá až po to D. Já mu pak musím říkat, že zašel moc daleko. Pro příště ale vím, že potřebuji dát víc kontextu k tomu, proč má v bodě A skončit,“&lt;/em&gt; ilustruje občasné komunikační střety zakladatelka. Doslovnost a analytický rozklad problémů se však startupu okamžitě vrací ve chvíli, kdy tým narazí na nekvalitní a chaotická data v zadání.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;„Cítím nespravedlnost. Jsem naštvaná na to, jakým způsobem se společnost staví k lidem, kteří jsou jiní. Ta jinakost nemusí být na první pohled patrná, ale znamená pro ně spoustu překážek, které jim vyrábíme my všichni. Angličtina pro to má slovní spojení ‚disabled by society‘. Jakmile mi ukážete něco takového, jsem totální buldok a jdu po narovnávání té nespravedlnosti,“ &lt;/em&gt;vysvětluje Zatloukalová, pro kterou se tak v Diversightu kromě společenského přesahu spojuje vášeň pro data a práce s lidmi. &lt;em&gt;„Baví mě dělat věci, které nikdo předtím moc nedělal nebo neprozkoumal. Diversight má v sobě všechno,“ &lt;/em&gt;uzavírá.&lt;/p&gt;
				&lt;/div&gt;

				
&lt;/div&gt;&lt;/div&gt;&lt;/body&gt;&lt;/html&gt;</content>
        <author>
            <name>Peter Brejčák</name>
        </author>
        <media:content medium="image" url="https://cc.cz/wp-content/uploads/2026/05/irena-zatloukalova.jpg"/>
        <source>
            <id>tag:feedly.com,2013:cloud/feed/https://feeds.buzzsprout.com/1104554.rss</id>
            <title type="html">CzechCrunch</title>
            <link href="https://cc.cz" rel="alternate" type="text/html"/>
            <updated>2026-05-07T05:33:01Z</updated>
        </source>
    </entry>
    <entry>
        <id>tag:feedly.com,2013:cloud/entry/cOXRjoksGIQzU1pdqbdybn+OTWYeI0riptNneGckdsI=_19dfd361137:57fe1:e753ea5d</id>
        <title type="html">Using safe-area-inset to build mobile-safe layouts</title>
        <published>2026-05-06T12:14:32Z</published>
        <updated>2026-05-06T12:14:35Z</updated>
        <link href="https://polypane.app/blog/using-safe-area-inset-to-build-mobile-safe-layouts/" rel="alternate" type="text/html"/>
        <summary type="html">Modern phones are not simple rectangles. They have rounded corners, camera cutouts, dynamic islands, and home indicators that double as gesture areas. Browsers…</summary>
        <content type="html">&lt;!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"&gt;
&lt;html&gt;&lt;body&gt;&lt;div&gt;&lt;div&gt;&lt;div id="article"&gt;&lt;p&gt;Modern phones are not simple rectangles. They have rounded corners, camera cutouts, dynamic islands, and home indicators that double as gesture areas. Browsers know the dimensions of all of these and expose the parts that could obscure content as &lt;strong&gt;safe area insets&lt;/strong&gt;.&lt;/p&gt;&lt;p&gt;The "safe area" is the portion of the screen that is guaranteed to be free from being obscured by system UI. The safe-area-inset is the measurement of how much space the system UI is taking up on each edge of the screen. By using these values in your CSS, you can make sure that important content and controls are not obscured by the system UI.&lt;/p&gt;&lt;p&gt;If you don't want your floating chat button to end up sitting behind the home indicator, where it's unreachable, you need to account for the safe area inset.&lt;/p&gt;&lt;h2 id="environment-variables-for-safe-area-insets"&gt;Environment variables for safe area insets&lt;/h2&gt;&lt;p&gt;With the safe-area-inset environment variables, you can make your layout adapt to the current device's safe area and avoid those bugs. The &lt;code&gt;env()&lt;/code&gt; function is how you read those values in CSS:&lt;/p&gt;&lt;div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;&lt;span&gt;body&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
  &lt;span&gt;padding-top&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;env&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;safe-area-inset-top&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
  &lt;span&gt;padding-right&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;env&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;safe-area-inset-right&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
  &lt;span&gt;padding-bottom&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;env&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;safe-area-inset-bottom&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
  &lt;span&gt;padding-left&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;env&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;safe-area-inset-left&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
&lt;span&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="browser-support"&gt;Browser support&lt;/h3&gt;&lt;p&gt;Safe-area-insets are &lt;strong&gt;baseline widely available&lt;/strong&gt;, which means you can use them in production today and be confident that they will work for almost all your users on mobile devices.&lt;/p&gt;&lt;p&gt;Since it's baseline widely available, you don't &lt;em&gt;really&lt;/em&gt; need to think about fallbacks but if you want to be extra safe, you can provide a fallback padding if the browser doesn't support &lt;code&gt;env()&lt;/code&gt;:&lt;/p&gt;&lt;div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;&lt;span&gt;body&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
  &lt;span&gt;padding-top&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; 1rem&lt;span&gt;;&lt;/span&gt; 
  &lt;span&gt;padding-top&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;calc&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;env&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;safe-area-inset-top&lt;span&gt;)&lt;/span&gt; + 1rem&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
&lt;span&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And for browsers that support &lt;code&gt;env()&lt;/code&gt; but not &lt;code&gt;safe-area-inset-*&lt;/code&gt; variables, you can provide a fallback value directly in the &lt;code&gt;env()&lt;/code&gt; function. If &lt;code&gt;safe-area-inset-top&lt;/code&gt; is not supported, it will fall back to &lt;code&gt;1rem&lt;/code&gt;:&lt;/p&gt;&lt;div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;&lt;span&gt;body&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
  &lt;span&gt;padding-top&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;env&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;safe-area-inset-top&lt;span&gt;,&lt;/span&gt; 1rem&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
&lt;span&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It's worth noting that this situation is purely theoretical, as all browsers that support &lt;code&gt;env()&lt;/code&gt; also support &lt;code&gt;safe-area-inset-*&lt;/code&gt; variables. That might not be the case with other environment variables, so it's good to know that this fallback mechanism exists.&lt;/p&gt;&lt;h2 id="using-safe-area-inset-values"&gt;Using safe-area-inset values&lt;/h2&gt;&lt;p&gt;Before we get into problem areas, let's get a general understanding of how these variables work and how you can use them to affect the layout.&lt;/p&gt;&lt;p&gt;In this demo, change each inset and watch how a realistic mobile UI that takes safe area insets into account shifts to remain usable:&lt;/p&gt;&lt;p&gt;The specific px values here are not particular to any specific device, the point is to show how the device sets these variables and how your layout can respond to them as they change.&lt;/p&gt;&lt;p&gt;On real devices, you can think of these values as constants. They're provided by the browser and while they might change when switching from portrait to landscape or between OS updates that change the device UI as well as simply differ per device, they don't change dynamically as the user scrolls or interacts with the page. The browser provides them as a constant value that you can use to ensure your content is not obscured by the system UI.&lt;/p&gt;&lt;h2 id="which-web-pages-actually-need-this"&gt;Which web pages actually need this?&lt;/h2&gt;&lt;p&gt;If you want your pages to look the best they can, all of them.&lt;/p&gt;&lt;p&gt;Browsers by default will prevent your site from being obscured by the notch or home indicator, so your content will be safe without any special handling. That does come with a downside, which is that the browser will give you a smaller viewport to reserve space:&lt;/p&gt;&lt;p&gt;You'll notice the edges here keep the site from being obscured, but they also don't look that great. Ideally we want the content to stretch edge-to-edge, but we want to make sure they're not obscured by system UI. To get that, you need to opt in to the full viewport and handle safe areas yourself.&lt;/p&gt;&lt;p&gt;To do so is a two-step process. First, you need to add &lt;code&gt;viewport-fit=cover&lt;/code&gt; to your meta viewport tag:&lt;/p&gt;&lt;div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt; &lt;span&gt;name&lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;"&lt;/span&gt;viewport&lt;span&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span&gt;content&lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;"&lt;/span&gt;width=device-width, viewport-fit=cover&lt;span&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This will make the browser stretch your page edge-to-edge:&lt;/p&gt;&lt;p&gt;As you can see, the content sits behind the notch/dynamic island. &lt;code&gt;viewport-fit=cover&lt;/code&gt; tells the browser that you want to be responsible for making sure your content is not obscured by the system UI.&lt;/p&gt;&lt;p&gt;And now we can move those elements away from behind the system UI using &lt;code&gt;env(safe-area-inset-*)&lt;/code&gt;.&lt;/p&gt;&lt;div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;&lt;span&gt;.content&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
  &lt;span&gt;padding-right&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;env&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;safe-area-inset-right&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
  &lt;span&gt;padding-left&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;env&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;safe-area-inset-left&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
&lt;span&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you opt into the full viewport, here are the kinds of things you now have to think about to make sure your content is not obscured by the system UI:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Fixed headers and navigation bars should have enough space above or below for the notch or home indicator&lt;/li&gt;&lt;li&gt;Floating chat or help buttons should remain inside the safe area&lt;/li&gt;&lt;li&gt;Full-screen dialogs and drawers should take up the right height without being obscured by the home indicator&lt;/li&gt;&lt;li&gt;Map or video controls near screen corners&lt;/li&gt;&lt;/ul&gt;&lt;h3 id="safe-area-inset-doesnt-provide-margins"&gt;Safe-area-inset doesn't provide margins&lt;/h3&gt;&lt;p&gt;Safe-area-insets are defined to be exactly the space that the system UI is taking up. That means they don't provide any margin between the system UI's edge and your content.&lt;/p&gt;&lt;p&gt;If you set padding to just the safe-area-inset value, your content will sit right up against the edge of the safe area, which is right up against the system UI.&lt;/p&gt;&lt;p&gt;To add some breathing room, you can add your own padding on top of the safe area insets by combining things with &lt;code&gt;calc()&lt;/code&gt;. This way you can ensure that your content is not only safe from being obscured but also has some space to breathe:&lt;/p&gt;&lt;div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;&lt;span&gt;body&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
  &lt;span&gt;padding-top&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;calc&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;env&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;safe-area-inset-top&lt;span&gt;)&lt;/span&gt; + 1rem&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
  &lt;span&gt;padding-right&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;calc&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;env&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;safe-area-inset-right&lt;span&gt;)&lt;/span&gt; + 1rem&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
  &lt;span&gt;padding-bottom&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;calc&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;env&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;safe-area-inset-bottom&lt;span&gt;)&lt;/span&gt; + 1rem&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
  &lt;span&gt;padding-left&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;calc&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;env&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;safe-area-inset-left&lt;span&gt;)&lt;/span&gt; + 1rem&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
&lt;span&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="safe-area-inset-only-has-non-zero-values-on-mobile-devices"&gt;Safe-area-inset only has non-zero values on mobile devices&lt;/h2&gt;&lt;p&gt;&lt;code&gt;env()&lt;/code&gt; is supported across browsers and platforms, but the &lt;code&gt;safe-area-inset-*&lt;/code&gt; variables really only have non-zero values on mobile devices.&lt;/p&gt;&lt;p&gt;Desktop browsers always return 0 because there is no UI on top of pages in desktop browsers. It's only on mobile devices that these values are non-zero and that you have to account for them.&lt;/p&gt;&lt;p&gt;That's exactly why these bugs are so easy to miss. If you test in the Chrome responsive view, the safe area insets will still be 0 and you won't see any issues during development.&lt;/p&gt;&lt;p&gt;Testing on real devices is often delegated to the end of the project. By then, making layout changes to accommodate safe areas can be expensive, and the bugs can slip through to production. Even worse, they often only affect users on certain devices, so they can go unnoticed for a long time.&lt;/p&gt;&lt;h2 id="polypanes-device-emulation-supports-safe-area-insets"&gt;Polypane's device emulation supports safe area insets&lt;/h2&gt;&lt;p&gt;Polypane is the first and only desktop browser to emulate safe area insets. Every device in Polypane has correct safe area inset values for both portrait and landscape orientations.&lt;/p&gt;&lt;p&gt;Here's Polypane showing the safe area insets in blue, and the small viewport height difference in pink:&lt;/p&gt;&lt;img src="https://polypane.app/static/insetviz-be77ee8c0ab29ccda899743cd9a9b339.png" alt="a device showing safe area and small viewport overlays in Polypane"&gt;&lt;p&gt;&lt;em&gt;We're also the only desktop browser to emulate &lt;code&gt;svh&lt;/code&gt;, but that's a topic for another article.&lt;/em&gt;&lt;/p&gt;&lt;p&gt;With Polypane's safe-area-inset &lt;strong&gt;overlay visualization&lt;/strong&gt;, you can see exactly where the unsafe areas are on each device.&lt;/p&gt;&lt;h2 id="solving-a-specific-issue-floating-buttons"&gt;Solving a specific issue: Floating buttons&lt;/h2&gt;&lt;p&gt;Let's look at a specific example of how to use &lt;code&gt;safe-area-inset&lt;/code&gt; values to solve a common issue: floating buttons that end up behind the home indicator and become unreachable.&lt;/p&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;&lt;span&gt;.chat-button&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
  &lt;span&gt;position&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; fixed&lt;span&gt;;&lt;/span&gt;
  &lt;span&gt;right&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; 10px&lt;span&gt;;&lt;/span&gt;
  &lt;span&gt;bottom&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; 10px&lt;span&gt;;&lt;/span&gt;
&lt;span&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Toggle the positioning between 'Fixed position' and 'Using env()' to switch between hard-coded offsets and offsets that use &lt;code&gt;safe-area-inset-bottom&lt;/code&gt; and &lt;code&gt;safe-area-inset-right&lt;/code&gt;.&lt;/p&gt;&lt;h2 id="safe-area-max-inset"&gt;&lt;code&gt;safe-area-max-inset&lt;/code&gt;&lt;/h2&gt;&lt;p&gt;Along with &lt;code&gt;safe-area-inset-*&lt;/code&gt;, the specification also describes &lt;code&gt;safe-area-max-inset-*&lt;/code&gt; variables. Those are not widely supported yet, but they are worth mentioning because they have slightly different behavior:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;safe-area-inset-*&lt;/code&gt;&lt;/strong&gt; gives you the &lt;em&gt;current&lt;/em&gt; inset value right now. On scroll, the browser chrome can collapse, and the inset value can shrink all the way to &lt;code&gt;0&lt;/code&gt;. Your element moves with that change.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;safe-area-max-inset-*&lt;/code&gt;&lt;/strong&gt; gives you the &lt;em&gt;maximum&lt;/em&gt; inset the browser can report for that edge. It stays stable even when the browser chrome collapses. Use it when you want a reserved zone that does not jump around.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;p&gt;Drag or scroll the phone to simulate the browser address bar appearing and disappearing.&lt;/p&gt;&lt;p&gt;The &lt;strong&gt;green button&lt;/strong&gt; uses &lt;code&gt;safe-area-inset-bottom&lt;/code&gt; and follows the current inset. The &lt;strong&gt;blue button&lt;/strong&gt; uses &lt;code&gt;safe-area-max-inset-bottom&lt;/code&gt; and stays put.&lt;/p&gt;&lt;p&gt;&lt;label&gt;Overlay&lt;/label&gt;&lt;label&gt;Show safe inset areas&lt;/label&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;p&gt;inset vs max-inset&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;When to use which really depends on your situation. For some UI components it makes sense to move with the live viewport state, like a floating chat button that should always be just above the home indicator.&lt;/p&gt;&lt;p&gt;For other things, like a persistent cookie banner or a full-screen dialog, it can be better to reserve a stable zone that doesn't shift when the browser chrome collapses so that users don't inadvertently tap the wrong button.&lt;/p&gt;&lt;div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;
&lt;span&gt;.floating-cta&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
  &lt;span&gt;bottom&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;calc&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;env&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;safe-area-inset-bottom&lt;span&gt;)&lt;/span&gt; + 1rem&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
&lt;span&gt;}&lt;/span&gt;


&lt;span&gt;.persistent-zone&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
  &lt;span&gt;bottom&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;calc&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;env&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;safe-area-max-inset-bottom&lt;span&gt;)&lt;/span&gt; + 1rem&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
&lt;span&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="browser-support-for-safe-area-max-inset-"&gt;Browser support for &lt;code&gt;safe-area-max-inset-*&lt;/code&gt;&lt;/h3&gt;&lt;p&gt;As of now, only Chromium implements &lt;code&gt;safe-area-max-inset-*&lt;/code&gt; so there is no support in (mobile) Safari or Firefox. That means you can't depend on it yet and should provide a fallback stack for other browsers:&lt;/p&gt;&lt;div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;&lt;span&gt;.bottom-spacer&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
  &lt;span&gt;padding-bottom&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; 1rem&lt;span&gt;;&lt;/span&gt;
  &lt;span&gt;padding-bottom&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;calc&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;env&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;safe-area-inset-bottom&lt;span&gt;)&lt;/span&gt; + 1rem&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
  &lt;span&gt;padding-bottom&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;calc&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;env&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;safe-area-max-inset-bottom&lt;span&gt;,&lt;/span&gt; &lt;span&gt;env&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;safe-area-inset-bottom&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt; + 1rem&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
&lt;span&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Notice how we're using the &lt;code&gt;env()&lt;/code&gt; fallback mechanism to fall back to &lt;code&gt;safe-area-inset-bottom&lt;/code&gt; if &lt;code&gt;safe-area-max-inset-bottom&lt;/code&gt; is not supported.&lt;/p&gt;&lt;h2 id="testing-safe-areas-in-polypane"&gt;Testing safe areas in Polypane&lt;/h2&gt;&lt;p&gt;As covered earlier, safe area bugs are easy to miss during development. Chrome's responsive view always reports inset values of 0, and real-device testing tends to get pushed to the end of the project, when fixing layout issues is expensive and bugs have already reached production.&lt;/p&gt;&lt;p&gt;Polypane changes that. You can test safe area insets (and small viewport behavior) directly on your desktop, across multiple devices and orientations simultaneously, as part of your normal development workflow.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Catch real-device layout failures during development, not after shipping.&lt;/strong&gt;&lt;/p&gt;&lt;img src="https://polypane.app/static/overlays-8190bd849571d99d1511f3cb9969653c.png" alt="mobile panes in Polypane showing visualized safe area and small viewport difference"&gt;&lt;h2 id="what-to-take-away"&gt;What to take away&lt;/h2&gt;&lt;p&gt;Safe areas are not edge cases for unusual devices. They are the reality of modern mobile devices with camera punch holes, notches, dynamic islands, and home indicator bars. Your users are on those devices, and if you want to give them the best experience, you need to make sure your content is not obscured by the system UI.&lt;/p&gt;&lt;p&gt;Make sure your viewport is set to &lt;code&gt;viewport-fit=cover&lt;/code&gt; so you get the full viewport and that you use &lt;code&gt;env(safe-area-inset-*)&lt;/code&gt; so all your content is visible and accessible. That gives users the best experience.&lt;/p&gt;&lt;p&gt;Get started with testing safe areas in Polypane today, and catch real-device layout failures during development, not after shipping.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/body&gt;&lt;/html&gt;</content>
        <author>
            <name/>
        </author>
        <media:content medium="image" url="https://polypane.app/og-images/using-safe-area-inset-to-build-mobile-safe-layouts.png"/>
        <source>
            <id>tag:feedly.com,2013:cloud/feed/https://polypane.app/rss.xml</id>
            <title type="html">polypane.app</title>
            <link href="https://polypane.app" rel="alternate" type="text/html"/>
            <updated>2026-05-06T12:14:35Z</updated>
        </source>
    </entry>
    <entry>
        <id>tag:feedly.com,2013:cloud/entry/cOXRjoksGIQzU1pdqbdybn+OTWYeI0riptNneGckdsI=_19df28a4f04:bf55cf:ff5f181c</id>
        <title type="html">Design Token Naming Conventions: A Practical Guide</title>
        <published>2026-05-04T10:30:43Z</published>
        <updated>2026-05-04T10:30:47Z</updated>
        <link href="https://www.alwaystwisted.com/articles/design-token-naming-conventions.html" rel="alternate" type="text/html"/>
        <summary type="html">A practical guide to naming design tokens, including token tiers, common conventions, and rules that keep systems consistent and scalable.</summary>
        <content type="html">&lt;!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"&gt;
&lt;html&gt;&lt;body&gt;&lt;div&gt;&lt;div&gt;&lt;article&gt;&lt;p&gt;
    
    &lt;/p&gt;&lt;h1&gt;Design Token Naming Conventions: A Practical Guide&lt;/h1&gt;
  
      &lt;time datetime="2026-04-23T00:00:00.000Z"&gt;23rd of April 2026&lt;/time&gt;&lt;details&gt;&lt;summary&gt;On This Page:&lt;/summary&gt;&lt;/details&gt;&lt;p&gt;If you have ever stared at a long token list and wondered whether a name should be &lt;code&gt;button-primary-bg&lt;/code&gt;, &lt;code&gt;primary-button-background&lt;/code&gt;, or &lt;code&gt;color-button-primary&lt;/code&gt;, you are not alone.&lt;/p&gt;
&lt;p&gt;Naming design tokens can look and feel simple right up until you have to do it for real. Choose a weak pattern and things get inconsistent fast. Choose a clear pattern and you get a shared language that helps both design and engineering move quicker.&lt;/p&gt;
&lt;p&gt;There is no single correct convention. A two-person team shipping one product has very different needs from a large organisation running multiple brands across multiple platforms.&lt;/p&gt;
&lt;p&gt;What you can do is pick a convention that is clear, consistent, and scalable. This article walks through the core token tiers, common naming models, and practical rules that help avoid naming drift.&lt;/p&gt;
&lt;h2 id="why-naming-gets-hard-faster-than-expected" tabindex="-1"&gt;Why naming gets hard faster than expected&lt;/h2&gt;
&lt;p&gt;Most teams don't struggle creating tokens. They struggle to keep token meaning stable as more people and components work on the Design System.&lt;/p&gt;
&lt;p&gt;You can often see multiple names emerge for the same idea:&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;Code language&lt;/span&gt;json&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;"spacing.small"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;"space-2"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;"gap-md"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;"paddingStandard"&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;Each name might make sense in isolation. Together, they signal a semantic drift. The naming model is no longer acting as a shared language.&lt;/p&gt;
&lt;p&gt;This is why naming quality can affect delivery speed. If token intent is unclear, every usage becomes a local judgement call, and those judgement calls will accumulate into inconsistency.&lt;/p&gt;
&lt;div&gt;&lt;svg&gt;&lt;/svg&gt;&lt;p&gt;The examples in this article follow the &lt;a href="https://www.designtokens.org"&gt;Design Tokens Community Group&lt;/a&gt; specification using &lt;code&gt;$value&lt;/code&gt;, &lt;code&gt;$type&lt;/code&gt;, and dot-notation aliases like &lt;code&gt;{color.brand.primary}&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;h2 id="what-are-design-tokens%2C-a-quick-recap" tabindex="-1"&gt;What are design tokens, a quick recap&lt;/h2&gt;
&lt;p&gt;Design tokens are a tooling and platform agnostic way to store design decisions as named values: colour, spacing, typography, radius, shadows, motion, and (much) more.&lt;/p&gt;
&lt;p&gt;The key difference is where and how many times you define those values.&lt;/p&gt;
&lt;p&gt;Without tokens, you might use &lt;code&gt;#BADA55&lt;/code&gt; in dozens of places across components, stylesheets, and design files. When that green needs to change, you might have to hunt down every instance to make sure you're updating everything that needs to be updated.&lt;/p&gt;
&lt;p&gt;With tokens, you create a design token file, a JSON object following the &lt;a href="https://www.designtokens.org"&gt;Design Tokens Community Group specification&lt;/a&gt;:&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;Code language&lt;/span&gt;json&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;{&lt;/span&gt;
  &lt;span&gt;"green"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
    &lt;span&gt;"400"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
      &lt;span&gt;"$value"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;"#BADA55"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
      &lt;span&gt;"$type"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;"color"&lt;/span&gt;
    &lt;span&gt;}&lt;/span&gt;
  &lt;span&gt;}&lt;/span&gt;
&lt;span&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;You define &lt;code&gt;#BADA55&lt;/code&gt; once as &lt;code&gt;green.400&lt;/code&gt;, then you can reference that name everywhere. The value is still defined somewhere, but it is defined in one place with a meaningful name and consumed by both design tools and code by reference via tooling like Tokens Studio or Style Dictionary.&lt;/p&gt;
&lt;p&gt;This centralisation helps to give you three major benefits:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;Better consistency across UI&lt;/li&gt;
&lt;li&gt;Easier theming and re-branding&lt;/li&gt;
&lt;li&gt;Safer changes at scale because you update once and propagate everywhere&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;Tokens are not just a technical detail. They are a shared language between design and development (and the whole team) that ends up in the product(s).&lt;/p&gt;
&lt;h2 id="the-three-token-tiers" tabindex="-1"&gt;The three token tiers&lt;/h2&gt;
&lt;p&gt;Most modern token workflows follow a three-tier model. You will see different names for each tier, but the same underlying structure keeps showing up.&lt;/p&gt;
&lt;h3 id="tier-1---primitive-tokens" tabindex="-1"&gt;Tier 1 - Primitive tokens&lt;/h3&gt;
&lt;p&gt;These are your raw values.&lt;/p&gt;
&lt;p&gt;They describe what something is, not why it exists.&lt;/p&gt;
&lt;p&gt;They are also referred to as reference, base, options, or global tokens.&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;Code language&lt;/span&gt;json&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;{&lt;/span&gt;
  &lt;span&gt;"blue"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
    &lt;span&gt;"500"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
      &lt;span&gt;"$value"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;"#0066CC"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
      &lt;span&gt;"$type"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;"color"&lt;/span&gt;
    &lt;span&gt;}&lt;/span&gt;
  &lt;span&gt;}&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
  &lt;span&gt;"spacing"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
    &lt;span&gt;"8"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
      &lt;span&gt;"$value"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;"8px"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
      &lt;span&gt;"$type"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;"dimension"&lt;/span&gt;
    &lt;span&gt;}&lt;/span&gt;
  &lt;span&gt;}&lt;/span&gt;
&lt;span&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;Primitives should not (imho) and are usually not consumed directly by components. They are source values for more specific design decisions and token tiers.&lt;/p&gt;
&lt;p&gt;A common failure is skipping straight to component naming because it feels productive in the short term. In practice, that locks in naming decisions before your core scales are stable.&lt;/p&gt;
&lt;p&gt;When possible, stabilise primitives first, attach intent later.&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;Code language&lt;/span&gt;json&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;{&lt;/span&gt;
  &lt;span&gt;"core"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
    &lt;span&gt;"dimension"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
      &lt;span&gt;"100"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;{&lt;/span&gt; &lt;span&gt;"$value"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;"8px"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;"$type"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;"dimension"&lt;/span&gt; &lt;span&gt;}&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
      &lt;span&gt;"200"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;{&lt;/span&gt; &lt;span&gt;"$value"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;"16px"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;"$type"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;"dimension"&lt;/span&gt; &lt;span&gt;}&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
      &lt;span&gt;"300"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;{&lt;/span&gt; &lt;span&gt;"$value"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;"24px"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;"$type"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;"dimension"&lt;/span&gt; &lt;span&gt;}&lt;/span&gt;
    &lt;span&gt;}&lt;/span&gt;
  &lt;span&gt;}&lt;/span&gt;
&lt;span&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;h3 id="tier-2---semantic-tokens" tabindex="-1"&gt;Tier 2 - Semantic tokens&lt;/h3&gt;
&lt;p&gt;Also known as alias, decision, theme, or system tokens.&lt;/p&gt;
&lt;p&gt;Semantic tokens can express intent. They describe why a value is used or what it is for.&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;Code language&lt;/span&gt;json&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;{&lt;/span&gt;
  &lt;span&gt;"color"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
    &lt;span&gt;"brand"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
      &lt;span&gt;"primary"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
        &lt;span&gt;"$value"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;"{blue.500}"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
        &lt;span&gt;"$type"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;"color"&lt;/span&gt;
      &lt;span&gt;}&lt;/span&gt;
    &lt;span&gt;}&lt;/span&gt;
  &lt;span&gt;}&lt;/span&gt;
&lt;span&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;This is where tokens become resilient.&lt;/p&gt;
&lt;p&gt;If brand blue changes, the semantic name can stay the same while the underlying primitive reference changes.&lt;/p&gt;
&lt;p&gt;You can update once and it will change everywhere.&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;Code language&lt;/span&gt;json&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;{&lt;/span&gt;
  &lt;span&gt;"layout"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
    &lt;span&gt;"spacing"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
      &lt;span&gt;"formStack"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;{&lt;/span&gt; &lt;span&gt;"$value"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;"{core.dimension.300}"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;"$type"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;"dimension"&lt;/span&gt; &lt;span&gt;}&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
      &lt;span&gt;"contentToButton"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
        &lt;span&gt;"$value"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;"{core.dimension.200}"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
        &lt;span&gt;"$type"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;"dimension"&lt;/span&gt;
      &lt;span&gt;}&lt;/span&gt;
    &lt;span&gt;}&lt;/span&gt;
  &lt;span&gt;}&lt;/span&gt;
&lt;span&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;h3 id="tier-3---component-tokens" tabindex="-1"&gt;Tier 3 - Component tokens&lt;/h3&gt;
&lt;p&gt;Also known as "component specific" or contextual tokens.&lt;/p&gt;
&lt;p&gt;This layer maps semantic intent to specific elements, components, and parts thereof.&lt;/p&gt;
&lt;p&gt;Component tokens should always reference semantic tokens, never primitives directly. That indirection is what can keep the system flexible.&lt;/p&gt;
&lt;p&gt;It is optional, but very useful in larger systems.&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;Code language&lt;/span&gt;json&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;{&lt;/span&gt;
  &lt;span&gt;"button"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
    &lt;span&gt;"primary"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
      &lt;span&gt;"background"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
        &lt;span&gt;"$value"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;"{color.brand.primary}"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
        &lt;span&gt;"$type"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;"color"&lt;/span&gt;
      &lt;span&gt;}&lt;/span&gt;
    &lt;span&gt;}&lt;/span&gt;
  &lt;span&gt;}&lt;/span&gt;
&lt;span&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;Component tokens give you precision. You can tune one component without creating side effects and explosions elsewhere.&lt;/p&gt;
&lt;h2 id="common-naming-conventions" tabindex="-1"&gt;Common naming conventions&lt;/h2&gt;
&lt;p&gt;There is no universal winner ... "It depends". Different teams will always optimise for different makeup, needs, and constraints.&lt;/p&gt;
&lt;p&gt;These diagrams show the core layers for each convention. Real-world usage may add optional layers like state or namespace for more specificity.&lt;/p&gt;
&lt;h3 id="1.-category-property-modifier-(cpm)" tabindex="-1"&gt;1. Category-Property-Modifier (CPM)&lt;/h3&gt;
&lt;div&gt;
  &lt;p&gt;
    &lt;span&gt;category&lt;/span&gt;
    &lt;span&gt;property&lt;/span&gt;
    &lt;span&gt;role&lt;/span&gt;
    &lt;span&gt;state&lt;/span&gt;
  &lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;This starts broad and gets more specific: category, property, role (and optionally state for interactions). It is easy to scan and keeps naming fairly lightweight.&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;Code language&lt;/span&gt;json&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;{&lt;/span&gt;
  &lt;span&gt;"color"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
    &lt;span&gt;"button"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
      &lt;span&gt;"primary"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
        &lt;span&gt;"hover"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
          &lt;span&gt;"$value"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;"{color.brand.primary-hover}"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
          &lt;span&gt;"$type"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;"color"&lt;/span&gt;
        &lt;span&gt;}&lt;/span&gt;
      &lt;span&gt;}&lt;/span&gt;
    &lt;span&gt;}&lt;/span&gt;
  &lt;span&gt;}&lt;/span&gt;
&lt;span&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;h3 id="2.-tier-based-naming" tabindex="-1"&gt;2. Tier-based naming&lt;/h3&gt;
&lt;div&gt;
  &lt;p&gt;
    &lt;span&gt;primitive&lt;/span&gt;
    &lt;span&gt;semantic&lt;/span&gt;
    &lt;span&gt;component&lt;/span&gt;
    &lt;span&gt;state&lt;/span&gt;
  &lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Here, the naming pattern changes depending on the tier. Primitives hold values, semantic tokens hold intent, and component tokens hold local UI decisions, which keeps each layer focused. The diagram shows the token tiers; actual nesting depth varies (e.g., primitives are often 2 layers, while component tokens may be 3+).&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;Code language&lt;/span&gt;json&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;{&lt;/span&gt;
  &lt;span&gt;"blue"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
    &lt;span&gt;"500"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
      &lt;span&gt;"$value"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;"#2196F3"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
      &lt;span&gt;"$type"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;"color"&lt;/span&gt;
    &lt;span&gt;}&lt;/span&gt;
  &lt;span&gt;}&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
  &lt;span&gt;"color"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
    &lt;span&gt;"brand"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
      &lt;span&gt;"primary"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
        &lt;span&gt;"$value"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;"{blue.500}"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
        &lt;span&gt;"$type"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;"color"&lt;/span&gt;
      &lt;span&gt;}&lt;/span&gt;
    &lt;span&gt;}&lt;/span&gt;
  &lt;span&gt;}&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
  &lt;span&gt;"button"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
    &lt;span&gt;"primary"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
      &lt;span&gt;"background"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
        &lt;span&gt;"$value"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;"{color.brand.primary}"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
        &lt;span&gt;"$type"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;"color"&lt;/span&gt;
      &lt;span&gt;}&lt;/span&gt;
    &lt;span&gt;}&lt;/span&gt;
  &lt;span&gt;}&lt;/span&gt;
&lt;span&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;h3 id="3.-object-property-modifier-(opm)" tabindex="-1"&gt;3. Object-Property-Modifier (OPM)&lt;/h3&gt;
&lt;div&gt;
  &lt;p&gt;
    &lt;span&gt;object&lt;/span&gt;
    &lt;span&gt;property&lt;/span&gt;
    &lt;span&gt;modifier&lt;/span&gt;
    &lt;span&gt;state&lt;/span&gt;
  &lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;This one starts with the UI object, then narrows to property and variant. It tends to feel natural in component-led workflows because it mirrors how teams talk about UI day to day.&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;Code language&lt;/span&gt;json&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;{&lt;/span&gt;
  &lt;span&gt;"button"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
    &lt;span&gt;"background"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
      &lt;span&gt;"primary"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
        &lt;span&gt;"hover"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
          &lt;span&gt;"$value"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;"{color.brand.primary-hover}"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
          &lt;span&gt;"$type"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;"color"&lt;/span&gt;
        &lt;span&gt;}&lt;/span&gt;
      &lt;span&gt;}&lt;/span&gt;
    &lt;span&gt;}&lt;/span&gt;
  &lt;span&gt;}&lt;/span&gt;
&lt;span&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;h3 id="4.-context-first-naming" tabindex="-1"&gt;4. Context-first naming&lt;/h3&gt;
&lt;div&gt;
  &lt;p&gt;
    &lt;span&gt;tier&lt;/span&gt;
    &lt;span&gt;category&lt;/span&gt;
    &lt;span&gt;property&lt;/span&gt;
    &lt;span&gt;modifier&lt;/span&gt;
  &lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Context (e.g., 'brand' or 'theme') comes first, followed by category, property, and modifier. This ensures you know the layer before the specific decision. That works well when the same semantic token needs to exist across several themes or brands.&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;Code language&lt;/span&gt;json&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;{&lt;/span&gt;
  &lt;span&gt;"brand"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
    &lt;span&gt;"color"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
      &lt;span&gt;"primary"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
        &lt;span&gt;"default"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
          &lt;span&gt;"$value"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;"{primitive.color.blue.500}"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
          &lt;span&gt;"$type"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;"color"&lt;/span&gt;
        &lt;span&gt;}&lt;/span&gt;
      &lt;span&gt;}&lt;/span&gt;
    &lt;span&gt;}&lt;/span&gt;
  &lt;span&gt;}&lt;/span&gt;
&lt;span&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;h3 id="5.-a-comprehensive-structure" tabindex="-1"&gt;5. A Comprehensive Structure&lt;/h3&gt;
&lt;div&gt;
  &lt;p&gt;
    &lt;span&gt;namespace&lt;/span&gt;
    &lt;span&gt;category&lt;/span&gt;
    &lt;span&gt;concept&lt;/span&gt;
    &lt;span&gt;property&lt;/span&gt;
    &lt;span&gt;variant&lt;/span&gt;
    &lt;span&gt;state&lt;/span&gt;
  &lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Each segment has a specific job, from namespace through to state. This comprehensive structure allows for up to 6 layers, but start with the core 5 and add as needed for complexity. Names are longer, but they are very explicit, which helps when multiple teams and brands share the same system. Nathan Curtis's article &lt;a href="https://medium.com/eightshapes-llc/naming-tokens-in-design-systems-9e86c7444676"&gt;Naming Tokens in Design Systems&lt;/a&gt; goes much deeper on this taxonomy, it's well worth a reading (and bookmarking).&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;Code language&lt;/span&gt;json&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;{&lt;/span&gt;
  &lt;span&gt;"acme"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
    &lt;span&gt;"color"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
      &lt;span&gt;"button"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
        &lt;span&gt;"background"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
          &lt;span&gt;"primary"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
            &lt;span&gt;"hover"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
              &lt;span&gt;"$value"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;"{acme.color.brand.primary}"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
              &lt;span&gt;"$type"&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;"color"&lt;/span&gt;
            &lt;span&gt;}&lt;/span&gt;
          &lt;span&gt;}&lt;/span&gt;
        &lt;span&gt;}&lt;/span&gt;
      &lt;span&gt;}&lt;/span&gt;
    &lt;span&gt;}&lt;/span&gt;
  &lt;span&gt;}&lt;/span&gt;
&lt;span&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;h2 id="handling-variants%2C-states%2C-and-modes" tabindex="-1"&gt;Handling variants, states, and modes&lt;/h2&gt;
&lt;p&gt;Whatever base naming model you choose, you still need clear, predictable state and variant placement patterns.&lt;/p&gt;
&lt;p&gt;One practical way to stay coherent is to define where each concept lives in the name:&lt;/p&gt;
&lt;ol&gt;&lt;li&gt;Variant: what version of the same thing it is (for example &lt;code&gt;primary&lt;/code&gt;, &lt;code&gt;secondary&lt;/code&gt;, &lt;code&gt;danger&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;State: how that version is currently behaving (for example &lt;code&gt;hover&lt;/code&gt;, &lt;code&gt;active&lt;/code&gt;, &lt;code&gt;disabled&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Mode: which environment it belongs to (for example &lt;code&gt;light&lt;/code&gt;, &lt;code&gt;dark&lt;/code&gt;, &lt;code&gt;highContrast&lt;/code&gt;)&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;If those three ideas float around in different positions, naming gets noisy fast.&lt;/p&gt;
&lt;h3 id="the-same-decision-in-different-conventions" tabindex="-1"&gt;The same decision in different conventions&lt;/h3&gt;
&lt;p&gt;These examples all express the same meaning: primary button background on hover in dark mode.&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;Code language&lt;/span&gt;json&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;[&lt;/span&gt;
  &lt;span&gt;"button.primary.background.hover.dark"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
  &lt;span&gt;"button-background-primary-hover-dark"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
  &lt;span&gt;"dark.button.primary.background.hover"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
  &lt;span&gt;"acme.color.button.background.primary.hover.dark"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
  &lt;span&gt;"theme.dark.component.button.primary.background.hover"&lt;/span&gt;
&lt;span&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;Pick one ordering model and enforce it consistently. Mixing these patterns inside one system is where discoverability starts to break down.&lt;/p&gt;
&lt;h3 id="variants" tabindex="-1"&gt;Variants&lt;/h3&gt;
&lt;p&gt;Variants describe alternatives at the same hierarchy level, not interaction changes.&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;Code language&lt;/span&gt;json&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;[&lt;/span&gt;
  &lt;span&gt;"button.primary.background"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
  &lt;span&gt;"button.secondary.background"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
  &lt;span&gt;"button.danger.background"&lt;/span&gt;
&lt;span&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;Equivalent variant naming in other conventions:&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;Code language&lt;/span&gt;json&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;[&lt;/span&gt;
  &lt;span&gt;"button-background-primary"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
  &lt;span&gt;"button-background-secondary"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
  &lt;span&gt;"button-background-danger"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
  &lt;span&gt;"component.button.background.primary"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
  &lt;span&gt;"component.button.background.secondary"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
  &lt;span&gt;"component.button.background.danger"&lt;/span&gt;
&lt;span&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;h3 id="states" tabindex="-1"&gt;States&lt;/h3&gt;
&lt;p&gt;States represent interaction or status changes for the same UI element. Keep state terms predictable (&lt;code&gt;hover&lt;/code&gt;, &lt;code&gt;active&lt;/code&gt;, &lt;code&gt;focus&lt;/code&gt;, &lt;code&gt;disabled&lt;/code&gt;) so engineers can find related tokens quickly.&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;Code language&lt;/span&gt;json&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;[&lt;/span&gt;
  &lt;span&gt;"button.primary.background.hover"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
  &lt;span&gt;"button.primary.background.active"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
  &lt;span&gt;"button.primary.background.disabled"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
  &lt;span&gt;"button.primary.background.focus"&lt;/span&gt;
&lt;span&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;The same state grouping works across naming styles:&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;Code language&lt;/span&gt;json&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;[&lt;/span&gt;
  &lt;span&gt;"button-background-primary-hover"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
  &lt;span&gt;"button-background-primary-active"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
  &lt;span&gt;"button-background-primary-focus"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
  &lt;span&gt;"button-background-primary-disabled"&lt;/span&gt;
&lt;span&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;Code language&lt;/span&gt;json&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;[&lt;/span&gt;
  &lt;span&gt;"component.button.background.primary.hover"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
  &lt;span&gt;"component.button.background.primary.active"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
  &lt;span&gt;"component.button.background.primary.focus"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
  &lt;span&gt;"component.button.background.primary.disabled"&lt;/span&gt;
&lt;span&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;h3 id="scale-sizes" tabindex="-1"&gt;Scale sizes&lt;/h3&gt;
&lt;p&gt;Scale tokens create consistent step-based sizing. Whether you use &lt;code&gt;xs-xl&lt;/code&gt; labels or numeric steps, use one scale pattern and apply it everywhere to avoid drift.&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;Code language&lt;/span&gt;json&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;{&lt;/span&gt;
  &lt;span&gt;"spacing.sm"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
  &lt;span&gt;"spacing.md"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
  &lt;span&gt;"spacing.lg"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;span&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;For type scales, the same rule applies: keep naming sequential so size relationships are obvious at a glance.&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;Code language&lt;/span&gt;json&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;"font.size.sm"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;"font.size.md"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;"font.size.lg"&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;h3 id="modes-and-themes" tabindex="-1"&gt;Modes and themes&lt;/h3&gt;
&lt;p&gt;Modes are contextual variants of the same decision (for example light and dark). The token purpose stays the same, only the value changes per mode.&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;Code language&lt;/span&gt;json&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;"color.background.default.light"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;"color.background.default.dark"&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;Other mode-placement patterns you will see in real systems:&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;Code language&lt;/span&gt;json&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;[&lt;/span&gt;
  &lt;span&gt;"light.color.background.default"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
  &lt;span&gt;"dark.color.background.default"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
  &lt;span&gt;"theme.light.color.background.default"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
  &lt;span&gt;"theme.dark.color.background.default"&lt;/span&gt;
&lt;span&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;Whichever pattern you choose, keep mode placement fixed. A stable suffix or a stable prefix both work; switching between them does not.&lt;/p&gt;
&lt;h3 id="numbered-scales" tabindex="-1"&gt;Numbered scales&lt;/h3&gt;
&lt;p&gt;Numbered scales are useful when you need many fine-grained steps, especially for colour ramps and heading systems. The key is to keep the numbering direction and increments consistent.&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;Code language&lt;/span&gt;json&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;[&lt;/span&gt;
  &lt;span&gt;"font.size.heading.1"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
  &lt;span&gt;"font.size.heading.2"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
  &lt;span&gt;"font.size.heading.3"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
  &lt;span&gt;"color.gray.50"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
  &lt;span&gt;"color.gray.100"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
  &lt;span&gt;"color.gray.200"&lt;/span&gt;
&lt;span&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;Numbered scales also appear in alternative patterns:&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;Code language&lt;/span&gt;json&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;[&lt;/span&gt;
  &lt;span&gt;"size-font-heading-100"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
  &lt;span&gt;"size-font-heading-200"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
  &lt;span&gt;"size-font-heading-300"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
  &lt;span&gt;"scale.type.heading.100"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
  &lt;span&gt;"scale.type.heading.200"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
  &lt;span&gt;"scale.type.heading.300"&lt;/span&gt;
&lt;span&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;h2 id="rules-that-keep-token-naming-healthy" tabindex="-1"&gt;Rules that keep token naming healthy&lt;/h2&gt;
&lt;p&gt;Most strong naming systems follow a predictable anatomy: an optional prefix (namespace or context), a core meaning (category and property), optional modifiers (intent, variant, scale), and an optional suffix (state or mode).&lt;/p&gt;
&lt;p&gt;You do not need every part in every token, but when a part is present it should always appear in the same position.&lt;/p&gt;
&lt;h3 id="1.-consistency-beats-perfection" tabindex="-1"&gt;1. Consistency beats perfection&lt;/h3&gt;
&lt;p&gt;The best naming system is the one your whole team actually follows.&lt;/p&gt;
&lt;p&gt;Drifting tends to start not where the convention is broken outright, but where it is ambiguous enough to invite interpretation. A token set that mixes naming styles makes it impossible to predict what a new token should be called.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Avoid:&lt;/strong&gt; mixing conventions across the same token tier&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;Code language&lt;/span&gt;json&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;[&lt;/span&gt;
  &lt;span&gt;"color.button.primary.default"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
  &lt;span&gt;"button.background.primary.hover"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
  &lt;span&gt;"theme.dark.component.button.primary.background.default"&lt;/span&gt;
&lt;span&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;&lt;strong&gt;Prefer:&lt;/strong&gt; one convention applied throughout&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;Code language&lt;/span&gt;json&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;[&lt;/span&gt;
  &lt;span&gt;"component.button.primary.background.default"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
  &lt;span&gt;"component.button.primary.background.hover"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
  &lt;span&gt;"component.button.secondary.background.default"&lt;/span&gt;
&lt;span&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;h3 id="2.-optimise-for-clarity-over-brevity" tabindex="-1"&gt;2. Optimise for clarity over brevity&lt;/h3&gt;
&lt;p&gt;Autocompletion means typing long names is rarely a problem, but reading a token list at a glance still relies on human pattern recognition. Abbreviating too aggressively trades a small typing convenience for an ongoing cognitive overhead every time someone reads or audits the system.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Avoid&lt;/strong&gt; abbreviations that require decoding&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;Code language&lt;/span&gt;json&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;"btn-bg-pri-hvr"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;"c-txt-err"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;"sp-md"&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;&lt;strong&gt;Prefer&lt;/strong&gt; names that read on first glance&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;Code language&lt;/span&gt;json&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;"button-background-primary-hover"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;"color-text-error"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;"spacing-md"&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;h3 id="3.-keep-semantics-semantic" tabindex="-1"&gt;3. Keep semantics semantic&lt;/h3&gt;
&lt;p&gt;A name like &lt;code&gt;color-text-red&lt;/code&gt; describes a visual value, which means the name breaks as soon as the colour changes. A name like &lt;code&gt;color-text-error&lt;/code&gt; describes intent, which stays stable even when the underlying value does not. At semantic and component levels, name for why, not what.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Avoid:&lt;/strong&gt; naming for the visual value&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;Code language&lt;/span&gt;json&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;"color.text.red"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;"color.background.grey"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;"color.border.green"&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;&lt;strong&gt;Prefer:&lt;/strong&gt; naming for the intent&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;Code language&lt;/span&gt;json&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;"color.text.error"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;"color.background.subtle"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;"color.border.success"&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;h3 id="4.-order-from-broad-to-specific" tabindex="-1"&gt;4. Order from broad to specific&lt;/h3&gt;
&lt;p&gt;Names are easier to scan when they move from the widest concept toward specificity. This also means that alphabetically sorted token lists naturally group related tokens together, which makes auditing and searching much faster.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Avoid:&lt;/strong&gt; specificity before category&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;Code language&lt;/span&gt;json&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;"hover.primary.button.color"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;"disabled.background.input"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;"lg.font.heading"&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;&lt;strong&gt;Prefer:&lt;/strong&gt; broad category first, narrowing toward specificity&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;Code language&lt;/span&gt;json&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;[&lt;/span&gt;
  &lt;span&gt;"color.button.primary.hover"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
  &lt;span&gt;"color.input.background.disabled"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
  &lt;span&gt;"font.heading.lg"&lt;/span&gt;
&lt;span&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;h3 id="5.-make-names-self-explanatory" tabindex="-1"&gt;5. Make names self-explanatory&lt;/h3&gt;
&lt;p&gt;A developer who has never seen your design tokens before should be able to make a reasonable guesstimate about what it does. If a name requires specific knowledge or a colleague to interpret, it is a candidate for renaming.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Avoid:&lt;/strong&gt; names that only make sense in context&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;Code language&lt;/span&gt;json&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;"token-1"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;"c-bd-x"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;"primary-a"&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;&lt;strong&gt;Prefer:&lt;/strong&gt; names that explain themselves&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;Code language&lt;/span&gt;json&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;[&lt;/span&gt;
  &lt;span&gt;"button.border.radius"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
  &lt;span&gt;"color.border.focus"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
  &lt;span&gt;"color.button.background.primary"&lt;/span&gt;
&lt;span&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;h3 id="6.-design-for-growth" tabindex="-1"&gt;6. Design for growth&lt;/h3&gt;
&lt;p&gt;Your naming model should be able to absorb more components, more themes, and potentially more brands without a heavy structural rewrite. That does not mean you need to "over engineer" from the start, but it does mean avoiding patterns that only work at small scale, like implicit positional meaning or naming steps after their current count.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Avoid:&lt;/strong&gt; patterns that hit a ceiling&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;Code language&lt;/span&gt;json&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;"spacing-small"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;"spacing-smaller"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;"spacing-new"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;"spacing-new-2"&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;&lt;strong&gt;Prefer:&lt;/strong&gt; a scale that can always grow in either direction&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;Code language&lt;/span&gt;json&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;"spacing.100"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;"spacing.200"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;"spacing.300"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;"spacing.420"&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;h2 id="choosing-your-convention" tabindex="-1"&gt;Choosing your convention&lt;/h2&gt;
&lt;p&gt;A practical way to decide is to consider your team size, system scope, tooling, and existing patterns together.&lt;/p&gt;
&lt;p&gt;Larger teams will need a stronger structure, single product systems can probably stay simpler, and tools like Figma, Tokens Studio, and your build pipeline may naturally favour one style.&lt;/p&gt;
&lt;p&gt;It is also usually safer to evolve existing patterns than replace everything at once, and the best outcome comes when designers and developers both buy into the same model.&lt;/p&gt;
&lt;p&gt;Start simple, document it clearly, add examples, and revisit as the system grows.&lt;/p&gt;
&lt;p&gt;Token names do not need to be academically perfect. They need to be clear enough that your team can apply them without hesitation.&lt;/p&gt;
&lt;h2 id="keep-naming-alive-with-lightweight-governance" tabindex="-1"&gt;Keep naming alive with lightweight governance&lt;/h2&gt;
&lt;p&gt;Naming is not a one time decision.&lt;/p&gt;
&lt;p&gt;It is an ongoing Design System practice.&lt;/p&gt;
&lt;p&gt;If you want conventions to hold up over time, define lightweight governance:&lt;/p&gt;
&lt;ol&gt;&lt;li&gt;One canonical naming guide with approved examples&lt;/li&gt;
&lt;li&gt;A short review checklist for new tokens&lt;/li&gt;
&lt;li&gt;Periodic cleanup of duplicate or ambiguous names&lt;/li&gt;
&lt;li&gt;Shared ownership across design and engineering&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;The goal is not "process for process' sake".&lt;/p&gt;
&lt;p&gt;A token system in a Design System that people trust is one they will actually use, and consistent naming is how that trust gets built.&lt;/p&gt;


    
      
      
    
    
    

  &lt;/article&gt;&lt;/div&gt;&lt;/div&gt;&lt;/body&gt;&lt;/html&gt;</content>
        <author>
            <name/>
        </author>
        <media:content medium="image" url="https://news.design.systems/embed?color1=ffffff&amp;amp;color2=2c2c2d&amp;amp;color_bg_button=2c2c2d&amp;amp;color_border=ccc&amp;amp;color_button=ffffff&amp;amp;color_links=979797&amp;amp;color_terms=808080&amp;amp;title=Subscribe+to+Design+Systems+News"/>
        <link href="/images/articles/meta-images/design-tokens-naming.png" rel="enclosure" type="image/png"/>
        <source>
            <id>tag:feedly.com,2013:cloud/feed/https://www.alwaystwisted.com/feed.xml</id>
            <title type="html">Always Twisted</title>
            <link href="https://www.alwaystwisted.com" rel="alternate" type="text/html"/>
            <updated>2026-05-04T10:30:47Z</updated>
        </source>
    </entry>
    <entry>
        <id>tag:feedly.com,2013:cloud/entry/cOXRjoksGIQzU1pdqbdybn+OTWYeI0riptNneGckdsI=_19ded75aef3:8a7f89:3a607295</id>
        <title type="html">Upgrading Forgejo with S3 Object Storage and Actions!</title>
        <published>2026-05-03T10:50:05Z</published>
        <updated>2026-05-03T10:50:09Z</updated>
        <link href="https://blog.alexsguardian.net/posts/2024/06/03/upgradingforgejo" rel="alternate" type="text/html"/>
        <summary type="html">Migrating my Forgejo server to s3 object storage and adding action runners for workflows!</summary>
        <content type="html">&lt;!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"&gt;
&lt;html&gt;&lt;body&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;hr&gt;&lt;p&gt;Awhile ago I spun up my own instance of Forgejo. &lt;a href="https://forgejo.org"&gt;Forgejo&lt;/a&gt;, if you are not familiar, is a hard fork of &lt;a href="https://gitea.com"&gt;Gitea&lt;/a&gt; when they became a &lt;em&gt;for-profit&lt;/em&gt; company and is run/managed by &lt;a href="https://codeberg.org"&gt;Codeberg&lt;/a&gt;. If you want more details on why Forgejo came to be, you can read their blog post &lt;a href="https://forgejo.org/2022-12-15-hello-forgejo/"&gt;here&lt;/a&gt;. As of now it’s basically a drop-in replacement for Gitea. Though over time this will change as the two projects drift apart. So it may not be one in the future! Anyhow, I’ve been rolling my own instance since September 2023 and, recently I have been moving my entire lab towards a more &lt;a href="https://about.gitlab.com/topics/gitops/"&gt;GitOps&lt;/a&gt; approach. To do this and do it securely (in the confines of my internal network), I’ve decided to turn Forgejo into my full CI/CD manager and config storage place. I’ll also be using &lt;a href="https://bitwarden.com/products/secrets-manager/"&gt;Bitwarden’s Secret Manager&lt;/a&gt; to manage, well, secrets.&lt;/p&gt;&lt;p&gt;Before I begin re-doing my lab for the umpteenth time, I need to change how Forgejo operates currently. That way Forgejo can support the transition from ‘FileOps’ (aka loose files) to GitOps. Now this isn’t the ‘perfect’ setup process as the repo storage still lives in /data, and it’s not currently replicated across my small swarm cluster. This will change when I get to actually rebuilding the cluster from the ground up to utilize NFS mounts for shared storage. Though that requires more hardware, which the wife probably won’t be happy about. &lt;span&gt;&#128517;&lt;/span&gt;&lt;/p&gt;&lt;h2 id="migrating-to-s3-object-storage"&gt;Migrating to S3 Object Storage&lt;/h2&gt;&lt;p&gt;Forgejo (in Docker), by default, has you map a &lt;code&gt;/data&lt;/code&gt; directory where all the necessary configs/repos/logs/etc. live. As you can see by the example compose file &lt;a href="https://forgejo.org/docs/latest/admin/installation-docker/"&gt;here&lt;/a&gt;.&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;docker-compose.yml&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;image&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;codeberg.org/forgejo/forgejo:7&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;./forgejo:/data&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;# &amp;lt;---- data volume&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;/etc/timezone:/etc/timezone:ro&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;/etc/localtime:/etc/localtime:ro&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;This is great if you plan on just running a simple setup, or you already have shared storage. For me though, I have no shared storage, and a &lt;a href="https://min.io/"&gt;MinIO&lt;/a&gt; server that is currently doing nothing but holding attachments for &lt;a href="https://github.com/outline/outline"&gt;Outline&lt;/a&gt;. I figured it’s time to put it to more use. That, and my day job involves doing AWS things so figured it would be good practice.&lt;/p&gt;&lt;p&gt;Currently, Forgejo supports the following directories (under &lt;code&gt;/appdata&lt;/code&gt;) for object storage.&lt;/p&gt;&lt;div&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;Subsystem&lt;/th&gt;&lt;th&gt;Directory&lt;/th&gt;&lt;th&gt;app.ini Sections&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Attachments&lt;/td&gt;&lt;td&gt;attachments/&lt;/td&gt;&lt;td&gt;[attachment]&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;LFS&lt;/td&gt;&lt;td&gt;lfs/&lt;/td&gt;&lt;td&gt;[lfs]&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Avatars&lt;/td&gt;&lt;td&gt;avatars/&lt;/td&gt;&lt;td&gt;[avatar]&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Repository avatars&lt;/td&gt;&lt;td&gt;repo-avatars/&lt;/td&gt;&lt;td&gt;[repo-avatar]&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Repository archives&lt;/td&gt;&lt;td&gt;repo-archive/&lt;/td&gt;&lt;td&gt;[repo-archive]&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Packages&lt;/td&gt;&lt;td&gt;packages/&lt;/td&gt;&lt;td&gt;[packages]&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Actions logs&lt;/td&gt;&lt;td&gt;actions_log/&lt;/td&gt;&lt;td&gt;[storage.actions_log]&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Actions Artifacts&lt;/td&gt;&lt;td&gt;actions_artifacts/&lt;/td&gt;&lt;td&gt;[actions.artifacts]&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;caption&gt;&lt;a href="https://forgejo.org/docs/latest/admin/storage/"&gt;Forgejo Docs: Storage Settings&lt;/a&gt;&lt;/caption&gt;&lt;/table&gt;&lt;/div&gt;&lt;p&gt;As you can see in the table above there are a few storage directories missing. Mainly repositories. Since repositories do not work well in object storage they are unsupported. Which means they will still be living on one of my hosts temporarily until I finalize my cross cluster storage solution. In order migrate the storage to MinIO, I first need to create a bucket (named &lt;code&gt;forgejo&lt;/code&gt;), an Access Identity, and an ACL for it.&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;access-credentials&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;Access_key:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;O3n9bNhrbadkeyAGKOuhIUzMGF&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;Secret_key:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;czgQT1fb1l3GD2nRQEPebadsecretbWG0xGIu20hjOeBfoSGo&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;Access Key User Policy&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;"s3:ListBucketMultipartUploads"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;"s3:AbortMultipartUpload"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;"s3:ListMultipartUploadParts"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;The above ACL replaces the default one under the “Current User Policy” after enabling the “ON” switch for “Restrict beyond user policy” setting in &lt;code&gt;User &amp;gt; Access Keys &amp;gt; Create access key&lt;/code&gt;. It limits the access key to the &lt;code&gt;forgejo&lt;/code&gt; bucket. The bucket is also private by default, so I do not have to change the bucket ACL.&lt;/p&gt;&lt;p&gt;&lt;img alt="Create Access Key" src="https://blog.alexsguardian.net/_astro/fj-create-access-key.2JyFthvY_11P6bC.webp"&gt;&lt;span&gt;MinIO Create Access Key with a custom user policy&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Next was to upload the existing files to MinIO so that when Forgejo restarted with the new s3 config it would pick them back up. As you can see in the picture below there are a few absent directories. I decided to condense a few related directories into parent ones for my ease of use. Also, some of them do not exist yet and will be created when needed (e.g. packages/).&lt;/p&gt;&lt;p&gt;&lt;img alt="forgejo bucket dir 1" src="https://blog.alexsguardian.net/_astro/fj-s3-dir_1.DFDEWvjv_wh5yr.webp"&gt;&lt;span&gt;Example MinIO bucket directory layout&lt;/span&gt;&lt;/p&gt;&lt;p&gt;My current s3 bucket directory layout:&lt;/p&gt;&lt;p&gt;With MinIO ready to go, all I had to do was update the Forgejo container environment variables for the MinIO connection and re-deploy. Forgejo environment variables can be defined using the &lt;code&gt;env -&amp;gt; ini&lt;/code&gt; notation. So in your &lt;code&gt;app.ini&lt;/code&gt; you have sections that are labeled, such as ‘[security].’ In order to update the INI value for say, ‘INSTALL_LOCK’, you’d need to define it as &lt;code&gt;FORGEJO__security__INSTALL_LOCK&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;As you can see in the example snippet file below, I am defining the MinIO connection information, as well as, where to look for specific directories in the bucket.&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;forgejo-minio-env-example&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__storage__STORAGE_TYPE="minio"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__storage__MINIO_USE_SSL="true"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__storage__MINIO_ENDPOINT="s3.${LAB_DOMAIN}"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__storage__MINIO_ACCESS_KEY_ID=${FJ_S3_ACCESS_ID}&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__storage__MINIO_SECRET_ACCESS_KEY=${FJ_S3_ACCESS_KEY}&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__storage__MINIO_BUCKET="forgejo"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__storage__MINIO_LOCATION="us-east-1"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__attachment__MINIO_BASE_PATH="attachments/"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__lfs__MINIO_BASE_PATH="lfs/"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__avatar__MINIO_BASE_PATH="avatars/users/"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__repo-avatar__MINIO_BASE_PATH="avatars/repositories/"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__repo-archive__MINIO_BASE_PATH="archives/"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__packages__MINIO_BASE_PATH="packages/"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__storage.actions_log__MINIO_BASE_PATH="actions/logs/"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__actions.artifacts__MINIO_BASE_PATH="actions/artifacts/"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;a name="compose-example"&gt;&lt;/a&gt;&lt;details&gt;&lt;summary&gt;Forgejo Compose Example [Expand me]&lt;/summary&gt;&lt;div&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;forgejo.yml&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;test&lt;/span&gt;&lt;span&gt;: [&lt;/span&gt;&lt;span&gt;"CMD"&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;"curl"&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;"-fSs"&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;"localhost:3000/api/healthz"&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;image&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;codeberg.org/forgejo/forgejo:7.0&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO_APP_NAME="Forgejo"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO_RUN_MODE="prod"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO_WORK_PATH="/data/gitea"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__repository__ROOT="/data/git/repositories"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__repository.local__LOCAL_COPY_PATH="/data/gitea/tmp/local-repo"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__repository.pull-request__DEFAULT_MERGE_STYLE="merge"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__repository.signing__DEFAULT_TRUST_MODEL="committer"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__server__APP_DATA_PATH="/data/gitea"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__server__DOMAIN="git.${LAB_DOMAIN}"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__server__SSH_DOMAIN="git.${LAB_DOMAIN}"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__server__HTTP_PORT="3000"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__server__ROOT_URL="https://git.${LAB_DOMAIN}"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__server__DISABLE_SSH="false"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__server__SSH_PORT="22"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__server__SSH_LISTEN_PORT="22"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__server__LFS_START_SERVER="true"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__server__LFS_JWT_SECRET="${FJ_JWT_SECRET}"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__server__OFFLINE_MODE="false"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__database__DB_TYPE="postgres"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__database__HOST="${FJ_DB_HOST}"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__database__NAME="${FJ_DB}"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__database__USER="${FJ_DB_USER}"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__database__PASSWD="${FJ_DB_PASS}"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__database__LOG_SQL="false"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__database__SCHEMA=""&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__database__SSL_MODE="disable"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__indexer__ISSUE_INDEXER_PATH="/data/gitea/indexers/issues.bleve"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__session__PROVIDER_CONFIG="/data/gitea/sessions"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__session__PROVIDER="file"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__session__COOKIE_SECURE="true"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__log__MODE="console"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__log__LEVEL="info"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__log__ROOT_PATH="/data/gitea/log"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__security__INSTALL_LOCK="true"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__security__SECRET_KEY="${FJ_SECRET_KEY}"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__security__REVERSE_PROXY_LIMIT="1"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__security__REVERSE_PROXY_TRUSTED_PROXIES="${CADDY_INT_IP}"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__security__INTERNAL_TOKEN="${FJ_INT_TOKEN}"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__security__PASSWORD_HASH_ALGO="${FJ_PASS_ALGO}"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__service__DISABLE_REGISTRATION="true"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__service__REQUIRE_SIGNIN_VIEW="false"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__service__REGISTER_EMAIL_CONFIRM="false"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__service__ENABLE_NOTIFY_MAIL="false"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__service__ALLOW_ONLY_EXTERNAL_REGISTRATION="false"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__service__ENABLE_CAPTCHA="true"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__service__CAPTCHA_TYPE="cfturnstile"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__service__REQUIRE_CAPTCHA_FOR_LOGIN="true"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__service__CF_TURNSTILE_SECRET="${FJ_CFT_SECRET}"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__service__CF_TURNSTILE_SITEKEY="${FJ_CFT_SITE_KEY}"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__service__DEFAULT_KEEP_EMAIL_PRIVATE="true"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__service__DEFAULT_ALLOW_CREATE_ORGANIZATION="true"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__service__DEFAULT_ENABLE_TIMETRACKING="true"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__service__NO_REPLY_ADDRESS="noreply@${FJ_DOMAIN}"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__mailier__ENABLED="false"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__openid__ENABLE_OPENID_SIGNIN="false"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__openid__ENABLE_OPENID_SIGNUP="false"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FROGEJO__cron.update_checker__ENABLED="false"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__oauth2__JWT_SECRET="${FJ_OAUTH_SEC}"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__actions__ENABLED="true"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__actions__DEFAULT_ACTIONS_URL="https://git.${LAB_DOMAIN}"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__actions__ARTIFACT_RETENTION_DAYS="90"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__storage__STORAGE_TYPE="minio"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__storage__MINIO_USE_SSL="true"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__storage__MINIO_ENDPOINT="s3.${LAB_DOMAIN}"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__storage__MINIO_ACCESS_KEY_ID=${FJ_S3_ACCESS_ID}&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__storage__MINIO_SECRET_ACCESS_KEY=${FJ_S3_ACCESS_KEY}&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__storage__MINIO_BUCKET="forgejo"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__storage__MINIO_LOCATION="us-east-1"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__attachment__MINIO_BASE_PATH="attachments/"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__lfs__MINIO_BASE_PATH="lfs/"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__avatar__MINIO_BASE_PATH="avatars/users/"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__repo-avatar__MINIO_BASE_PATH="avatars/repositories/"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__repo-archive__MINIO_BASE_PATH="archives/"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__packages__MINIO_BASE_PATH="packages/"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__storage.actions_log__MINIO_BASE_PATH="actions/logs/"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;FORGEJO__actions.artifacts__MINIO_BASE_PATH="actions/artifacts/"&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;/etc/timezone:/etc/timezone:ro&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;/etc/localtime:/etc/localtime:ro&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;aside&gt;&lt;p&gt;&lt;svg&gt;&lt;/svg&gt; Tip&lt;/p&gt;&lt;section&gt;&lt;p&gt;If you are curious about all the configuration options for Forgejo, you can check out the configuration cheat sheet &lt;a href="https://forgejo.org/docs/latest/admin/config-cheat-sheet/"&gt;here&lt;/a&gt;.&lt;/p&gt;&lt;/section&gt;&lt;/aside&gt;&lt;/div&gt;&lt;/details&gt;&lt;p&gt;With the environment variables updated, and a quick redeploy of Forgejo, I was up and running with object storage via MinIO! A quick trip into the &lt;code&gt;Site Administration &amp;gt; Configuration &amp;gt; Summary&lt;/code&gt; in Forgejo shows that LFS was now using MinIO as seen in the below image.&lt;/p&gt;&lt;p&gt;&lt;img alt="FJ Site Admin Config for LFS" src="https://blog.alexsguardian.net/_astro/fj-site-admin.BuBy27dw_1f0fNQ.webp"&gt;&lt;span&gt;Forgejo site admin config showing LFS using MinIO&lt;/span&gt;&lt;/p&gt;&lt;h2 id="setting-up-forgejo-actions"&gt;Setting up Forgejo Actions&lt;/h2&gt;&lt;p&gt;&lt;img alt="FJ Actions Meme" src="https://blog.alexsguardian.net/_astro/fj_actions_meme.CHp604cc_1rm3bC.webp"&gt;&lt;/p&gt;&lt;p&gt;All jokes aside, Forgejo Actions is actually fairly decent. The runner is not production ready (according to &lt;a href="https://code.forgejo.org/forgejo/runner#forgejo-runner"&gt;Forgejo themselves&lt;/a&gt;) but it works well enough that I am going all in on it for my lab. Setting up the action runner was fairly straight forward. It’s got a similar setup process to the self-hosted GitHub runner.&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Enable Actions in the &lt;code&gt;app.ini&lt;/code&gt; or using environment variables. Restart/Redeploy Forgejo.&lt;/li&gt;&lt;/ol&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://blog.alexsguardian.net/posts/2024/06/03/upgradingforgejo#compose-example"&gt;See above&lt;/a&gt; for an example using environment variables under &lt;code&gt;#Actions Configs&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;ol start="2"&gt;&lt;li&gt;Create a new runner in &lt;code&gt;Site Administration &amp;gt; Actions &amp;gt; Runners &amp;gt; Create new runner&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;Copy the new runner registration token.&lt;/li&gt;&lt;li&gt;Deploy Forgejo Runner and register it with the token from step 3.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Now there are a few ways you could deploy the runner, but I decided to deploy it in Docker. You can bind the runner container to the Docker sock, but I did not. I really do not like doing that so, I ended up using &lt;a href="https://hub.docker.com/_/docker"&gt;Docker in Docker (DIND)&lt;/a&gt;. It’s not really recommended to use Docker this way but for my lab it will do fine. The compose file was also pretty easy to set up.&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;forgejo-actions.yml&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;command&lt;/span&gt;&lt;span&gt;: [&lt;/span&gt;&lt;span&gt;'dockerd'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;'-H'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;'tcp://0.0.0.0:2375'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;'--tls=false'&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;image&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;code.forgejo.org/forgejo/runner:3.4.1&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;condition&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;service_started&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;command&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;'/bin/sh -c "while : ; do sleep 1 ; done ;"'&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;# Change to this command after registration&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;#command: '/bin/sh -c "sleep 5; forgejo-runner daemon"'&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;DOCKER_HOST=tcp://dind:2375&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;As you can see above there are two &lt;code&gt;commands:&lt;/code&gt;. &lt;code&gt;'/bin/sh -c "while : ; do sleep 1 ; done ;"'&lt;/code&gt; starts up the runner container and does nothing. This allows you to enter the container via &lt;code&gt;docker exec&lt;/code&gt; and run the registration command using the token generated in the Site Administration settings. After registering the container, it can be brought down and the current command can be replaced with the commented out one (&lt;code&gt;'/bin/sh -c "sleep 5; forgejo-runner daemon"'&lt;/code&gt;). Then after redeploying the container the runner will become available in Forgejo globally. Having a global runner means it can be used by all repositories. Which for me works fine since my Forgejo instance is mainly private except for a few public repositories and a few GitHub mirrors.&lt;/p&gt;&lt;p&gt;&lt;img alt="FJ Manage Runners" src="https://blog.alexsguardian.net/_astro/fj-manage-runners.Bgx3xUe8_ZdqLTf.webp"&gt;&lt;span&gt;Forgejo Manage Runners&lt;/span&gt;&lt;/p&gt;&lt;p&gt;With my runner online and working, I am now able to have workflows kick off from steps defined in files located in &lt;code&gt;.forgejo/workflows/&lt;/code&gt;. The syntax is fairly similar to GitHub actions so most of the actions you can run there can run in Forgejo. The best part is I can mirror the action repositories and have my runner pull them directly from my Forgejo instance. The first thing I set up was Renovate Bot to keep my Docker images updated. The bot runs on a cron based workflow as seen below and opens a PR for image updates.&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;.forgejo/workflows/renovate.yml&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;cron&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;'0 0/6 * * *'&lt;/span&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;# every 6 hours, every day&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;RENOVATE_REPOSITORIES&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;${{ github.repository }}&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;${{ secrets.RENOVATE_TOKEN != '' }}&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;image&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;renovate/renovate:full&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;          &lt;/span&gt;&lt;span&gt;GITHUB_COM_TOKEN&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;${{ secrets.RENOVATE_GITHUB_COM_TOKEN }}&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;          &lt;/span&gt;&lt;span&gt;RENOVATE_BASE_DIR&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;${{ github.workspace }}/.tmp&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;          &lt;/span&gt;&lt;span&gt;RENOVATE_ENDPOINT&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;${{ github.server_url }}&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;          &lt;/span&gt;&lt;span&gt;RENOVATE_REPOSITORY_CACHE&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;'enabled'&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;          &lt;/span&gt;&lt;span&gt;RENOVATE_TOKEN&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;${{ secrets.RENOVATE_TOKEN }}&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;          &lt;/span&gt;&lt;span&gt;RENOVATE_GIT_AUTHOR&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;'Renovate Bot &amp;lt;renovate@mydomain.dev&amp;gt;'&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;          &lt;/span&gt;&lt;span&gt;GIT_AUTHOR_NAME&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;'Renovate'&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;          &lt;/span&gt;&lt;span&gt;GIT_AUTHOR_EMAIL&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;'renovate@mydomain.dev'&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;          &lt;/span&gt;&lt;span&gt;GIT_COMMITTER_NAME&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;'Renovate Bot'&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;          &lt;/span&gt;&lt;span&gt;GIT_COMMITTER_EMAIL&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;'renovate@mydomain.dev'&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;Get Ntfy Token from SM&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;uses&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;actions/sm-action@v4&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;access_token&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;${{ secrets.BITWARDEN_LAB_KEY }}&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span&gt;some-secret-id-string &amp;gt; NTFY_TOKEN&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span&gt;some-secret-id-string &amp;gt; LAB_DOMAIN&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;uses&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;actions/ntfy-action@master&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;          &lt;/span&gt;&lt;span&gt;url&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;'https://ntfy.${LAB_DOMAIN}'&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;          &lt;/span&gt;&lt;span&gt;headers&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;'{"authorization": "bearer $NTFY_TOKEN"}'&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;          &lt;/span&gt;&lt;span&gt;details&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;Renovate Bot failed to run!&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;The bot is configured via a &lt;code&gt;renovate.json&lt;/code&gt; file located in the root of the repository.&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;renovate.json&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;"$schema"&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;"https://docs.renovatebot.com/renovate-schema.json"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;"extends"&lt;/span&gt;&lt;span&gt;: [&lt;/span&gt;&lt;span&gt;"config:base"&lt;/span&gt;&lt;span&gt;],&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;"assignees"&lt;/span&gt;&lt;span&gt;: [&lt;/span&gt;&lt;span&gt;"alexandzors"&lt;/span&gt;&lt;span&gt;],&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;"dependencyDashboard"&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;"labels"&lt;/span&gt;&lt;span&gt;: [&lt;/span&gt;&lt;span&gt;"maintenance"&lt;/span&gt;&lt;span&gt;],&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;"enabledManagers"&lt;/span&gt;&lt;span&gt;: [&lt;/span&gt;&lt;span&gt;"docker-compose"&lt;/span&gt;&lt;span&gt;],&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;"fileMatch"&lt;/span&gt;&lt;span&gt;: [&lt;/span&gt;&lt;span&gt;"^.*&lt;/span&gt;&lt;span&gt;\\&lt;/span&gt;&lt;span&gt;.yml$"&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;"managers"&lt;/span&gt;&lt;span&gt;: [&lt;/span&gt;&lt;span&gt;"docker-compose"&lt;/span&gt;&lt;span&gt;],&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;"depTypeList"&lt;/span&gt;&lt;span&gt;: [&lt;/span&gt;&lt;span&gt;"services"&lt;/span&gt;&lt;span&gt;],&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;"datasources"&lt;/span&gt;&lt;span&gt;: [&lt;/span&gt;&lt;span&gt;"docker"&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;At the moment I have it scanning through all YAML files since I do not name my compose files &lt;code&gt;docker-compose.yml&lt;/code&gt;. They are named as the service so: &lt;code&gt;forge.yml&lt;/code&gt;, &lt;code&gt;caddy.yml&lt;/code&gt;, &lt;code&gt;authelia.yml&lt;/code&gt;, etc. They are also located in their own folders. This will be changing as I move more to GitOps but for now it’s fine.&lt;/p&gt;&lt;p&gt;&lt;img alt="FJ Renovate PR" src="https://blog.alexsguardian.net/_astro/fj-renovate-pr.BKbIoFtc_28Kiq4.webp"&gt;&lt;span&gt;PR Opened by Renovate Bot using the Forgejo Action workflow&lt;/span&gt;&lt;/p&gt;&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;&lt;p&gt;This was a fun project to work on in between work and family stuff. Hopefully this inspires one of you to upgrade your own local git setup with an ‘Actions’ runner or object storage! I’ll have a full config dump for MinIO, Forgejo, Forgejo Actions, and an example workflow in the &lt;a href="https://github.com/alexandzors/blog-files/tree/main/posts/upgradingforgejo"&gt;blog-files repo&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;&lt;em&gt;On to the next project. &lt;span&gt;&#128640;&lt;/span&gt;&lt;/em&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/body&gt;&lt;/html&gt;</content>
        <author>
            <name/>
        </author>
        <media:content medium="image" url="https://blog.alexsguardian.net/_astro/fj_actions_banner.Ly7zaxsc_C1Dxb.webp"/>
    </entry>
    <entry>
        <id>tag:feedly.com,2013:cloud/entry/cOXRjoksGIQzU1pdqbdybn+OTWYeI0riptNneGckdsI=_19ded720baf:89c617:5071632d</id>
        <title type="html">Rebuilding My Home Lab</title>
        <published>2026-05-03T10:46:07Z</published>
        <updated>2026-05-03T10:46:12Z</updated>
        <link href="https://blog.alexsguardian.net/posts/2025/02/25/rebuildingmyhomelab" rel="alternate" type="text/html"/>
        <summary type="html">Rebuilding my homelab 'cluster' into a proper 'cluster'.</summary>
        <content type="html">&lt;!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"&gt;
&lt;html&gt;&lt;body&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;p&gt;&lt;sub&gt;FTC: Some links in this post are income earning affiliate links.&lt;/sub&gt;&lt;/p&gt;&lt;p&gt;It’s been a while since I last posted about my homelab or well posted on the blog. So I figured I’d start off with a banger for 2025. Rebuilding my homelab into a Docker Swarm cluster that supports high availability. Hope you’re ready for a ride, because this was definitely a journey. &lt;span&gt;&#128517;&lt;/span&gt;&lt;/p&gt;&lt;sub&gt;&lt;em&gt;Side note: I also recently acquired a Bambu Lab A1 3D printer (with the AMS :)) to replace my old Anet A8. I’d say it’s mine, but I’ve only been printing stuff for my wife so far..&lt;/em&gt;&lt;/sub&gt;&lt;h2 id="the-plan"&gt;The Plan&lt;/h2&gt;&lt;p&gt;The plan for this project was to:&lt;/p&gt;&lt;ol type="a"&gt;&lt;li&gt;Create a cluster that supported high availability &lt;span&gt;✅&lt;/span&gt;&lt;/li&gt;&lt;li&gt;Setup a distributed storage solution that supported the above &lt;span&gt;✅&lt;/span&gt;&lt;/li&gt;&lt;li&gt;Setup a load balancer &lt;span&gt;✅&lt;/span&gt;&lt;/li&gt;&lt;li&gt;Have the cluster communicate over 2.5gb or faster networking &lt;span&gt;✅&lt;/span&gt;&lt;/li&gt;&lt;li&gt;Have a minimum of 3 nodes &lt;span&gt;✅&lt;/span&gt;&lt;/li&gt;&lt;li&gt;Be small and efficient &lt;span&gt;✅&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Easy enough right?… &lt;em&gt;right?&lt;/em&gt;&lt;/p&gt;&lt;p&gt;Since I had two Dell Optiplex 5050 Micros that I was using already, I decided to grab a third micro to complete the 3 node cluster. As for the actual orchestration software I decided to stick with Docker and use Docker Swarm. I’m a Docker guy but never had a chance to use Swarm properly with a shared storage system. Figured it was time to give it a proper go.&lt;/p&gt;&lt;div&gt;&lt;strong&gt;Wait… Docker Swarm? Alex you should use Kubernetes!!!!!!&lt;/strong&gt;&lt;img alt="Dwight Schrute saying 'Let's put it this way... no' from The Office" src="https://media4.giphy.com/media/v1.Y2lkPTc5MGI3NjExeWZ2eWN6czc3NWN1OXJyeDRvZ210azVzamF4ejNzejVkeWQ3djZkdCZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/daPCSjwus6UR2JxRX1/giphy.gif"&gt;&lt;/div&gt;&lt;h2 id="current-v2-cluster-specs"&gt;Current v2 Cluster Specs&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;2x Dell Optiplex 5050 Micros&lt;/li&gt;&lt;li&gt;1x Dell Optiplex 7040 Micros&lt;/li&gt;&lt;li&gt;3x Realtek 8125B 2.5gb A+E NICs&lt;/li&gt;&lt;li&gt;3x Intel 700p 256GB SSDs&lt;/li&gt;&lt;li&gt;3x Crucial BX500 1TB SSDs&lt;/li&gt;&lt;li&gt;Ubiquiti Flex-2.5g Switch&lt;/li&gt;&lt;li&gt;Ubuntu 24.04 LTS&lt;/li&gt;&lt;li&gt;GlusterFS&lt;/li&gt;&lt;/ul&gt;&lt;h2 id="cluster-v1"&gt;Cluster v1&lt;/h2&gt;&lt;sub&gt;circa 2023&lt;/sub&gt;&lt;p&gt;Cluster v1 never actually made it to ‘production’. It ended up being a test bed and a learning experience on gotchas when it came to Linux, Intel, drivers, and poor research on my part…&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;TLDR:&lt;/strong&gt; I originally bought some Intel i225-v 2.5gb m.2 cards from IOCrest thinking they’d work. Come to find out these particular chips have some &lt;a href="https://duckduckgo.com/?t=h_&amp;amp;q=intel+225-v+linux+driver+issues&amp;amp;ia=web" target="_blank"&gt;driver issues&lt;/a&gt; on Linux (specifically Ubuntu).&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;When originally designing the cluster I had planned on using M.2 2.5g cards since the Micro’s had M.2 M-key slots. That way I could get a less expensive SATA SSD for storage. After doing some research I settled on some &lt;a href="https://www.aliexpress.us/item/3256805389320511.html" target="_blank"&gt;Intel 225-V 2.5g cards&lt;/a&gt; from IOCrest on AliExpress. The one downside to these cards was the vertical connector pins. The chassis did not have enough space with a SATA SSD installed. So I did what any tinkerer would do and replaced the pins with right angle ones. The first two cards went good, but my old soldering iron doesnt keep temp well. On the third card’s NIC module I messed up and destroyed one of the traces. So I had to fix it with a jumper wire. Live and learn I suppose.&lt;/p&gt;&lt;p&gt;As for the NICs themselves, I started experiencing driver issues after getting two of the nodes up and running in a ‘mock’ swarm. These issues manifested as random disconnects or complete NIC power loss. I tried to fix it by messing with grub configs for pcie_aspm thinking it was related to Active State Power Management (ASPM) at first. I then tried manually setting the autonegotiation via ethtool. Also double checked UEFI settings, etc. Nothing seemed to work. So I ended up scrapping the Intel cards and going with Realtek 8125B cards for cluster v2.&lt;/p&gt;&lt;p&gt;Anyways, I’ll leave you with a few pictures from the v1 prototype, and we can move on to v2.&lt;/p&gt;&lt;h2 id="cluster-v2"&gt;Cluster v2&lt;/h2&gt;&lt;sub&gt;circa 2024&lt;/sub&gt;&lt;p&gt;My second attempt at the cluster faired a bit better. Well mostly (more on that later). After my first purchase mistake I went back and bought &lt;a href="https://www.aliexpress.us/item/3256803984886712.html" target="_blank"&gt;different M.2 adapters&lt;/a&gt;. These were A+E keyed and used the WLAN slot rather than the M.2 M-keyed slot which got freed up for more storage. These new adapters also use a Realtek chipset (8125B) rather than an Intel one. So no more odd driver issues.&lt;/p&gt;&lt;p&gt;&lt;img alt="M.2 A+E keyed adapter installed" src="https://blog.alexsguardian.net/_astro/PXL_20241022_172523762.MP.CizhE_LT_1pzDqf.webp"&gt;&lt;span&gt;M.2 A+E keyed adapter installed&lt;/span&gt;&lt;/p&gt;&lt;p&gt;With the new adapters using the A+E slot, I decided to use the M slot for a boot drive and the SATA port for cluster storage. For the boot drive I went with some Intel 700p 256GB SSDs I bought off someone from the Ubiquiti Discord server. As for cluster storage I went with &lt;a href="https://amzn.to/4hCYdg4" target="_blank"&gt;1TB Crucial BX500 SSDs&lt;/a&gt; from Amazon. These are not the fastest drives by any means but for my use case they should do just fine.&lt;/p&gt;&lt;p&gt;&lt;img alt="Storage SSDs" src="https://blog.alexsguardian.net/_astro/PXL_20241023_170004511.MP.ZdGI53cL_Z1W8jpI.webp"&gt;&lt;span&gt;Storage SSDs&lt;/span&gt;&lt;/p&gt;&lt;p&gt;There was one downside to the Intel SSDs though. Their physical size. They are 2230 and the Micro chassis only supports 2260 and 2280. So in order to use them I had to print out some 2230 to 2280 adapter brackets. I also printed out a 2.5in tray for the third Micro since it did not come with one. The print files are linked below.&lt;/p&gt;&lt;h3 id="the-os"&gt;The OS&lt;/h3&gt;&lt;p&gt;For the OS I decided to stick with my tried and true &lt;a href="https://ubuntu.com/server"&gt;Ubuntu &lt;strong&gt;Server&lt;/strong&gt;&lt;/a&gt; (24.04 LTS btw). It’s stable and easy to manage. Though, I may eventually re-image to &lt;a href="https://rockylinux.org/"&gt;Rocky Linux&lt;/a&gt; for easy live patching when I rebuild again. The process was pretty standard. I booted via my &lt;a href="https://netboot.xyz/"&gt;netboot.xyz&lt;/a&gt; PXE server, ran through the installer and then used &lt;a href="https://docs.ansible.com/"&gt;Ansible&lt;/a&gt; to configure the OS. I’ll have the playbooks + task files in the blog-files repo after this post is live.&lt;/p&gt;&lt;aside&gt;&lt;p&gt;&lt;svg&gt;&lt;/svg&gt; Tip&lt;/p&gt;&lt;section&gt;&lt;p&gt;Looking at getting started with Ansible? I highly recommend Jeff Geerling’s &lt;a href="https://www.ansiblefordevops.com/"&gt;Ansible for DevOps&lt;/a&gt; handbook.&lt;/p&gt;&lt;/section&gt;&lt;/aside&gt;&lt;aside&gt;&lt;p&gt;&lt;svg&gt;&lt;/svg&gt; Tip&lt;/p&gt;&lt;section&gt;&lt;p&gt;If you want to know more about the netboot.xyz server, Techno Tim has a great video on it &lt;a href="https://www.youtube.com/watch?v=4btW5x_clpg&amp;amp;pp=ygUSdGVjaG5vIHRpbSBuZXRib290"&gt;here&lt;/a&gt;.&lt;/p&gt;&lt;/section&gt;&lt;/aside&gt;&lt;video&gt;&lt;source src="https://blog.alexsguardian.net/_astro/ansible_prep.BIf03Imk.webm" type="video/webm"&gt;Your browser does not support webm.&lt;/source&gt;&lt;/video&gt;&lt;span&gt;Ansible playbook running on the cluster nodes&lt;/span&gt;&lt;h3 id="networking"&gt;Networking&lt;/h3&gt;&lt;p&gt;After the OS was set up on all the nodes, I went ahead configured the network interfaces. During the v2 build Ubiquiti launched their Flex 2.5g switch line. Since this was an SFF cluster the &lt;a href="https://store.ui.com/us/en/category/all-switching/products/usw-flex-2-5g-5" target="_blank"&gt;Flex Mini 2.5g&lt;/a&gt; was a perfect fit as the cluster’s network backbone. Also with it being powered by POE made for one less cable to deal with. The cluster network is also a fairly simple one. It has no access to the internet and no access to any other networks. Other networks also can’t access it. Don’t need stuff snooping on my unencrypted SQL traffic..&lt;/p&gt;&lt;p&gt;With the network interfaces configured and working, it was time to test the speed using &lt;a href="https://iperf.fr/" target="_blank"&gt;iperf&lt;/a&gt;. As you can see by the short video below, I was able to get roughly 2.5gbps of bandwidth between the nodes.&lt;/p&gt;&lt;video&gt;&lt;source src="https://blog.alexsguardian.net/_astro/cluster_speed.Crkfr9Hw.webm" type="video/webm"&gt;Your browser does not support webm.&lt;/source&gt;&lt;/video&gt;&lt;span&gt;iperf testing&lt;/span&gt;&lt;h3 id="distributed-file-system"&gt;Distributed File System&lt;/h3&gt;&lt;p&gt;This was probably the most difficult part of the cluster build. At the time I had really no experience dealing with distributed file systems. I narrowed down my options to GlusterFS and Ceph. I ended up going with &lt;a href="https://www.gluster.org/" target="_blank"&gt;GlusterFS&lt;/a&gt; for this iteration. Using the &lt;a href="https://docs.gluster.org/en/main/Quick-Start-Guide/Quickstart/" target="_blank"&gt;official documentation&lt;/a&gt; I was able to get a basic cluster up and running fairly quickly. I also created a dedicated Docker user ‘doc’ and set its home directory to the GlusterFS volume on each of the nodes. I thought this would be a great idea, but it ended up being a pain later on.&lt;/p&gt;&lt;p&gt;&lt;img alt="GlusterFS setup" src="https://blog.alexsguardian.net/_astro/gluster-setup.1YBYIxUu_Z1NJ65g.webp"&gt;&lt;span&gt;GlusterFS setup&lt;/span&gt;&lt;/p&gt;&lt;h3 id="docker-swarm"&gt;Docker Swarm&lt;/h3&gt;&lt;p&gt;With the OS, Networking, and DFS setup, it was time to set up Docker Swarm. Setting up Docker and Docker Swarm is fairly straight forward using the &lt;a href="https://docs.docker.com/engine/install/ubuntu/" target="_blank"&gt;official documentation&lt;/a&gt;. You basically follow the installation on each of the nodes. Then you initialize the swarm on one and join the other nodes to it. In my case my commands were:&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;sudo&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;docker&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;swarm&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;init&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--advertise-addr&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;192.168.100.2&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;## init the swarm on the cluster network interface&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;sudo&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;docker&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;swarm&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;join&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--token&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;SWMTKN-1-4c2d6gncjh15gaznem5m8t2twwfn09o0paqpjxwdkqr1n76h8j-chr42vcbaobx7v2nrk86q9e93&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;192.168.100.2:2377&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;## joining other nodes to the swarm&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;I then promoted the other two nodes to managers. This way I had proper high availability as it requires a minimum of 3 managers to be in the swarm.&lt;/p&gt;&lt;p&gt;&lt;img alt="Docker Swarm cluster" src="https://blog.alexsguardian.net/_astro/swarm-cluster.MJ-L-vim_2ga04o.webp"&gt;&lt;span&gt;Docker Swarm cluster&lt;/span&gt;&lt;/p&gt;&lt;h3 id="keepalived"&gt;Keepalived&lt;/h3&gt;&lt;p&gt;Next up was setting up &lt;a href="https://www.keepalived.org/" target="_blank"&gt;Keepalived&lt;/a&gt; to handle &lt;a href="https://en.wikipedia.org/wiki/Virtual_Router_Redundancy_Protocol" target="_blank"&gt;VRRP&lt;/a&gt; for the cluster. This allowed me to have a single IP address that automatically failed over to the next node automatically. The video below shows the failover in action (sped up to keep the video short).&lt;/p&gt;&lt;video&gt;&lt;source src="https://blog.alexsguardian.net/_astro/keepalived_node_switching.JYJzVdxF.webm" type="video/webm"&gt;Your browser does not support webm.&lt;/source&gt;&lt;/video&gt;&lt;span&gt;Keepalived VRRP failover&lt;/span&gt;&lt;p&gt;As you can see the active node switches as each keepalived service is terminated. The lower right shows a constant ping to the VRRP virtual IP (VIP). In this case 10.8.8.11. Having this VIP allows me to bring down hosts for maintenance or updates without having to worry about service connectivity.&lt;/p&gt;&lt;h3 id="ha-caddy"&gt;HA Caddy&lt;/h3&gt;&lt;p&gt;The final step before I could start using the cluster was to set up a load balancer/reverse proxy. There are a few different options but, if you’ve read any of my &lt;a href="https://blog.alexsguardian.net/tag/caddy" target="_blank"&gt;previous posts&lt;/a&gt; you know I love using &lt;a href="https://caddyserver.com/" target="_blank"&gt;Caddy&lt;/a&gt;. With its easy-to-use configuration and automatic certificate management makes it hard to beat. Also, Caddy is a great choice for this since it automatically clusters itself if all instances use the same storage volume.&lt;/p&gt;&lt;p&gt;First thing I did was create the new overlay network for Caddy. This network would be for any services that I wanted to be able to access from outside the cluster.&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;sudo&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;docker&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;network&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;create&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--opt&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;encrypted=&lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--driver&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;overlay&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--attachable&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--internal&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--subnet=172.0.96.0/20&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;caddy-internal&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;Creating the Caddy service file.&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;caddy.yml&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;image&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;alexandzors/caddy:2.9.1&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;/swarm/volumes/doc/caddy/Caddyfile:/etc/caddy/Caddyfile:ro&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;/swarm/volumes/doc/caddy/.data:/data&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;/swarm/volumes/doc/caddy/configs:/etc/caddy/configs:ro&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;Then deploying Caddy to the swarm.&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;sudo&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;docker&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;stack&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;deploy&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--c&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;caddy.yml&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;caddy&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;&lt;img alt="docker service ls command showing Caddy" src="https://blog.alexsguardian.net/_astro/deployed_caddy.Ci8ZMIoI_1MONUY.webp"&gt;&lt;span&gt;docker service ls command showing Caddy running on all 3 nodes&lt;/span&gt;&lt;/p&gt;&lt;p&gt;I eventually need to update the Caddy deployment to use host mode for port assignments. That way I can get the source IP address of incoming requests and not the docker proxy IP. But that will be part of v3.&lt;/p&gt;&lt;h2 id="cluster-v3"&gt;Cluster v3&lt;/h2&gt;&lt;sub&gt;circa 2025&lt;/sub&gt;&lt;p&gt;So here we are. Cluster v2 has been running great for a while now, but I’ve been having some issues with it. The main, and arguably the largest, issue I have been running into is the slow performance of GlusterFS. I’m not sure if it’s the hardware choices I made, or a misconfiguration? I tried the performance tuning tips from the &lt;a href="https://docs.gluster.org/en/main/Administrator-Guide/Performance-Tuning/" target="_blank"&gt;official documentation&lt;/a&gt; but was still running into issues. Like switching to the cluster user ‘doc’ would take anywhere from 30 to 45 seconds to complete. Also, deploying stacks of services could take up to 5 minutes before they were alive and running.&lt;/p&gt;&lt;p&gt;Either way for v3 I’m probably going to move to &lt;a href="https://ceph.com/" target="_blank"&gt;Ceph&lt;/a&gt; as my DFS solution. Since it seems to be the more popular of the two after digging around more. I may need to upgrade the RAM on the nodes to handle it though. I’m also going to try and add a 4th node to the cluster with beefier hardware since I still have one 2.5g port left on the switch. Maybe one with some GPU compute to handle local LLMs?&lt;/p&gt;&lt;p&gt;&lt;img alt="docker services ls" src="https://blog.alexsguardian.net/_astro/docker_services_ls.GNY8tZvm_Z1uGAAF.webp"&gt;&lt;span&gt;Current services running on the cluster&lt;/span&gt;&lt;/p&gt;&lt;p&gt;However, what won’t be changing is my use of Docker Swarm. &lt;span&gt;&#128521;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/body&gt;&lt;/html&gt;</content>
        <author>
            <name/>
        </author>
        <media:content medium="image" url="https://blog.alexsguardian.net/_astro/rebuild_banner.AfLrHjH8_ZS3Mfz.webp"/>
    </entry>
    <entry>
        <id>tag:feedly.com,2013:cloud/entry/cOXRjoksGIQzU1pdqbdybn+OTWYeI0riptNneGckdsI=_19de73bd2a9:21797a:4bf1e6c6</id>
        <title type="html">How to smoke</title>
        <published>2026-05-02T05:49:10Z</published>
        <updated>2026-05-02T05:49:14Z</updated>
        <link href="https://buttondown.com/monteiro/archive/how-to-smoke/" rel="alternate" type="text/html"/>
        <summary type="html">I used to love to smoke. If it weren’t for the whole lung cancer, emphysema, death thing, would you recommend smoking?</summary>
        <content type="html">&lt;!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"&gt;
&lt;html&gt;&lt;body&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;
    
        &lt;figure&gt;&lt;img alt="Four zippo lighters stacked up, sitting on pink paper." src="https://assets.buttondown.email/images/c2f95460-4ccf-4823-a800-01c37d5a8ced.jpeg?w=960&amp;amp;fit=max"&gt;&lt;figcaption&gt;&lt;em&gt;The best part of smoking was always the click of the Zippo.&lt;/em&gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;hr&gt;&lt;p&gt;&lt;em&gt;This week’s question comes to us from Mat Honan:&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I used to love to smoke. If it weren’t for the whole lung cancer, emphysema, death thing, would you recommend smoking?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;You’re forgetting the smell.&lt;/p&gt;
&lt;p&gt;Last week I was coming back from the record store and feeling lazy, so I jumped on the bus. A couple of stops after I got on, a dude got on and sat down next to me. Well-dressed dude, also carrying an Amoeba Records shopping bag. Out and about on a Sunday afternoon, doing his record shopping just like me. Within seconds it became clear this dude had &lt;em&gt;just&lt;/em&gt; had a cigarette. And he stunk. The bus was also packed at this point, so I was pretty much stuck in that seat until I got off, which luckily wasn’t for too much longer. Also, it feels kinda shitty when you sit down next to somebody on the bus and they immediately get up. (Unless you’re getting a creeper vibe, of course.) I just had to suck it up for a few more stops. But man, it was rough. I’m not trying to disparage the guy or anything. Especially because I used to be that guy, and you used to be that guy, and I’m guessing a lot of our readers used to be that guy. We just walked around smelling awful.&lt;/p&gt;
&lt;p&gt;Which is not to say that’s the worst part of smoking, but you took lung cancer, emphysema, and the dead thing off the table. Which leaves us with the smell.&lt;/p&gt;
&lt;p&gt;I started smoking my freshman year in college. All reasons to take up smoking are stupid, but this one might be the stupidest. This being the mid-80s our dorm had a cigarette machine in the lobby. One of those old machines you might still see in old man dive bars, with two rows of big ka-chunky knobs, which felt objectively good to pull. It was like you could feel the entire mechanism of the machine come to life when you pulled that knob. And it took some strength to do it! But you could feel the knob hit a gear, you could hear the gear spin, you could feel a pack of cigarettes get pushed free from deep inside the machine. You could hear it slide down a little ramp, and then you’d see it appear down in the landing zone, where you’d push your hand past the trap door, grab it, and somehow have the pack open, and a cigarette in your mouth before the rest of the pack hit your pocket.&lt;/p&gt;
&lt;p&gt;If memory serves, a pack of smokes was between $1.25 and $1.50 around that time. (Fun fact, I attempted to Google this and the slop top on the search results page said 26¢ a pack, which is… not true. But please, continue to rebuild society around such amazing technology.) Being the art school miscreants that we were, and also broke, we discovered that if you pulled a knob halfway out, inserted a quarter, and then pulled the knob the rest of the way out it would release a pack of cigarettes. (Ok, that may not have been the &lt;em&gt;actual&lt;/em&gt; process, but it was a long time ago, and it’s very close to the &lt;em&gt;spirit&lt;/em&gt; of the actual process, so let’s run with it. So I guess we &lt;em&gt;were&lt;/em&gt; getting a pack of cigarettes for what Google’s stupid slop robot said, but it included doing crimes.) The knowledge of how to hack the cigarette machine spread through the dorms like wildfire, and soon we were all smoking. Because we were idiots. Also, it felt like we were getting one over on The Man. But mostly because we were idiots.&lt;/p&gt;
&lt;p&gt;Also, being art school kids we were very visually-driven people, and all the photos of cool people that we’d hang up in our dorm rooms showed them holding a cigarette. And we very much wanted to be cool people. (True fact: take a photo of Humphrey Bogart, replace the ever-present cigarette with a vape and Humphrey Bogart will look like an herb.) Again, mostly we were idiots. &lt;/p&gt;
&lt;p&gt;The vending machine company tried to patch the hack several times, eventually gave up and just took the machine away. This was our first lesson that sometimes doing crime is in the public interest, but that lesson didn’t occur to us right away. At the time, we were just pissed that we had to pay retail for cigarettes again. &lt;/p&gt;
&lt;p&gt;By the time I started smoking society was pretty much done with the pretense that smoking was doing anything but murdering you slowly. I know this because we’d sit around in art classes making collages using old cigarette ads where doctors would tell you smoking was good for your nerves, and we would laugh at people for believing this, as we lit cigarette after cigarette. (Yes, you could smoke in class.) And we thought “Boy, our grandparents sure were chumps for believing cigarettes were healthy.” Then we would have a coughing fit. But there was definitely the sense that doing this thing that we all knew had a very very high probability of killing us wasn’t a big deal, mostly because we were in our 20s when nothing can hurt you, Reagan was president and, just to reiterate—we were idiots.&lt;/p&gt;
&lt;p&gt;My first post-college job was at a copy shop, and you got one 15 minute break during your shift. Unless you smoked, then you could get as many breaks as you needed. Several people started smoking while working there.&lt;/p&gt;
&lt;p&gt;We all stunk. We’d come in from smoking out back, and immediately walk up to the service counter to help a customer. A customer who either stunk as bad as we did, or had become inured to the stench because it was all around them, emanating from everyone.&lt;/p&gt;
&lt;p&gt;We smoked in class. We smoked at the movies. We smoked at the supermarket. We smoked at sporting events. My friend Jeff, who grew up in Boston, tells a good story about going to Celtics games as a kid and having to look past the hovering cloud of smoke between the cheap seats and the court. We smoked in restaurants, where the smoking and non-smoking sections were often divided by nothing more than a paper sign denoting the territorial boundary. We smoked on planes, man.&lt;/p&gt;
&lt;p&gt;It wasn’t too long after college that the world began to shift. In 2003 New York City banned smoking in bars. And I was visiting at the time. By 2003, I was no longer “a smoker” but I was very much someone who would look for reasons to bum a smoke from someone if the situation arose, and very likely to put myself in situations where it might. But I remember the rage from several friends and from the owners and bartenders of any bar we’d walk into. The ban was going to kill bars all over the city. It was going to kill nightlife. It was going to completely take down the economy. New York, as we know it, would cease to exist. Which of course, it didn’t. Everyone adjusted. They went outside. They eventually started smoking less because it was cold outside. People enjoyed being able to hang out in rooms that weren’t making them sick, and they enjoyed going home not reeking of cigarette smoke. If I could go back in time I’d reassure all those bartenders that it wasn’t the smoking ban they had to worry about. It was the kids who’d stop going out at all because they needed to sit at home and tend to their AI agents. &lt;/p&gt;
&lt;p&gt;I selected your question this week because I’ve actually been thinking of the smoking ban lately. We grew up in a time when smoking, or dealing with other smokers was an inevitability. Even if you didn’t smoke, you’d most likely work next to someone who did, or sit down next to someone who did at a restaurant, or at the movies. And even if they weren’t actively smoking, and covering you in second-hand smoke, you’d go home with the stench of smoke all over you. Airing your clothes out was an inevitability. Having to wash the stench out of your hair was an inevitability. Society smoked, so you did too. Whether you wanted to or not. And then it changed. Most cities in America now have smoking bans and rules about how far away you have to be from a public entrance to smoke, which get enforced to various degrees. &lt;/p&gt;
&lt;p&gt;The change came in a couple of very interesting ways. One, cigarettes are now hovering between $12 to $14 a pack. (I had to look this up!) They’re also available in less places. (You used to be able to buy cigarettes at the drug store!) Secondly, people just look at you weird if you start smoking now. Like, what the fuck dude, did you just light a cigarette!? Are you from the past? Gross.&lt;/p&gt;
&lt;p&gt;Which of course makes me think of some of the things that we have currently accepted as a society, things which we &lt;em&gt;fully know&lt;/em&gt; are not healthy for society, that we are currently tolerating. And also thinking there’s no way it will ever change, because we appear to be in an era of “what if everyone modeled themselves off the stupidest people?”&lt;/p&gt;
&lt;p&gt;Right now there is someone firing up ChatGPT because it’s cheap. Right now there is someone writing a prompt in Claude because it brings him closer to his co-workers. Right now there is someone walking a co-worker through his agentic workflow, in the same way we attempted to impress one another by blowing smoke rings. Right now there is someone parking a Cybertruck on your street, believing that leaving his divorce where everyone can see it is somehow impressive. We have always been good at ignoring the warnings that came with the pack. &lt;/p&gt;
&lt;p&gt;Our parents packed their homes with asbestos. They heated their homes with coal. They packed their Big Macs in styrofoam. Making mistakes will always be cheaper than fixing them. But nothing is more expensive than ignoring them. &lt;/p&gt;
&lt;p&gt;Cultural norms are an ever-changing thing. History is the story of what was once desirable becoming unacceptable. Something that used to be an inevitability is no longer inevitable. Something that used to be tolerated is no longer tolerated. Something that was seen as a cultural norm no longer is. Even when those things were backed by entire industries with very strong lobbies, as the tobacco lobby once was. The same fate will someday befall the NRA. The same fate will someday befall AIPAC. The same fate will someday befall the slop lobby.&lt;/p&gt;
&lt;p&gt;There was a time we thought if we prohibited people from smoking in bars it would lead to societal collapse. I think it was a good idea. More importantly, it was an idea that worked. It improved not just our personal health but the health of our communities.&lt;/p&gt;
&lt;p&gt;The basic strategy of all addictive technologies is very simple. They make you feel extra capable, they addict you, then they make you feel inadequate without them. They start by making you feel cool, and confident. Relax. Put your feet up. Hang with the fellas. Social anxiety? It’s toasted, dog! Let me write that résumé for you. Anniversary card for your wife? I can write that for you. Light one up. It’s a great way to start a relationship. But that initial boost eventually turns to reliance, and suddenly you can’t get out of bed without a hit. You can’t write your kid a love note without firing up a slop engine. And suddenly an entire industry is telling you that you’re not capable of moving through your day without their help. An entire industry gaslighting you, until it becomes easier to just gaslight yourself into believing that you were never truly capable of things you are very much capable of.&lt;/p&gt;
&lt;p&gt;I don’t miss smoking. Maybe I did at one point. But eventually the whiff of cigarette smoke went from smelling nostalgic to just smelling bad. Thankfully, knock on wood, I’ve been able to escape years of smoking without any &lt;em&gt;major&lt;/em&gt; lasting effects, but trust that I carry every pack I ever smoked with me every time I walk up a flight of stairs. If I’m doing anything strenuous, it’s always my lungs that give up first. &lt;/p&gt;
&lt;p&gt;Thankfully, I still have some lung capacity. I enjoy using it. You should too.&lt;/p&gt;
&lt;p&gt;&#128684;&lt;/p&gt;
&lt;hr&gt;&lt;p&gt;&#128587; Got a question? &lt;a href="https://www.mikemonteiro.com/ask-a-question?utm_source=monteiro&amp;amp;utm_medium=email&amp;amp;utm_campaign=how-to-smoke" rel="noopener noreferrer nofollow" target="_blank"&gt;Ask it&lt;/a&gt;! I will somewhat answer it!&lt;/p&gt;
&lt;p&gt;&#128211; Get your sexy copy of my new book &lt;a href="https://www.mulebooks.com/store/how-to-die-and-other-stories?utm_source=monteiro&amp;amp;utm_medium=email&amp;amp;utm_campaign=how-to-smoke" rel="noopener noreferrer nofollow" target="_blank"&gt;How to Die (and other stories)&lt;/a&gt;! And if you’re in the Bay Area, &lt;a href="https://booksmith.com/event/monteiro26?utm_source=monteiro&amp;amp;utm_medium=email&amp;amp;utm_campaign=how-to-smoke" rel="noopener noreferrer nofollow" target="_blank"&gt;come see me and Annalee Newitz talk about it on May 11 at Booksmith&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;&#128674; My friend Lucy Bellwood made a &lt;a href="https://lucybellwood.com/new-comic-the-scale-of-a-man/?utm_source=monteiro&amp;amp;utm_medium=email&amp;amp;utm_campaign=how-to-smoke" rel="noopener noreferrer nofollow" target="_blank"&gt;wonderful comic about loss and building&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&#128581; My friend Jason Cosper made a &lt;a href="https://jasoncosper.com/kill-yr-substack/?utm_source=monteiro&amp;amp;utm_medium=email&amp;amp;utm_campaign=how-to-smoke" rel="noopener noreferrer nofollow" target="_blank"&gt;great tool for fucking with Substack’s dollar&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&#128227; I’ve got a few seats left in next week’s &lt;a href="https://www.eventbrite.com/e/1987951529539?aff=oddtdtcreator&amp;amp;utm_source=monteiro&amp;amp;utm_medium=email&amp;amp;utm_campaign=how-to-smoke" rel="noopener noreferrer nofollow" target="_blank"&gt;Presenting w/Confidence&lt;/a&gt; workshop where you can learn &lt;em&gt;true&lt;/em&gt; confidence. The one inside you.&lt;/p&gt;
&lt;p&gt;&#127817; Please support &lt;a href="https://www.pcrf.net/?utm_source=monteiro&amp;amp;utm_medium=email&amp;amp;utm_campaign=how-to-smoke" rel="noopener noreferrer nofollow" target="_blank"&gt;the children of Palestine&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&#127987;️‍⚧️ Please &lt;a href="https://translifeline.org/?utm_source=monteiro&amp;amp;utm_medium=email&amp;amp;utm_campaign=how-to-smoke" rel="noopener noreferrer nofollow" target="_blank"&gt;support trans kids&lt;/a&gt;. And if there is a trans person in your life please tell them you love them.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
    
&lt;/div&gt;


                


    &lt;/div&gt;&lt;/div&gt;&lt;/body&gt;&lt;/html&gt;</content>
        <author>
            <name/>
        </author>
        <media:content medium="image" url="https://assets.buttondown.email/images/c2f95460-4ccf-4823-a800-01c37d5a8ced.jpeg?w=960&amp;fit=max"/>
        <source>
            <id>tag:feedly.com,2013:cloud/feed/https://buttondown.com/monteiro/rss</id>
            <title type="html">buttondown.com</title>
            <link href="https://buttondown.com" rel="alternate" type="text/html"/>
            <updated>2026-05-02T05:49:14Z</updated>
        </source>
    </entry>
</feed>