<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[Daniel Lopes]]></title><description><![CDATA[Notes from running engineering, product and design at GrowthX: decisions, reflections and ideas as they happen.
]]></description><link>https://journal.daniellopes.dev</link><image><url>https://substackcdn.com/image/fetch/$s_!cDim!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2713e243-3a29-434e-afb6-b7731174629f_512x512.png</url><title>Daniel Lopes</title><link>https://journal.daniellopes.dev</link></image><generator>Substack</generator><lastBuildDate>Tue, 25 Aug 2026 15:43:00 GMT</lastBuildDate><atom:link href="https://journal.daniellopes.dev/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Daniel Lopes]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[daniellopes@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[daniellopes@substack.com]]></itunes:email><itunes:name><![CDATA[Daniel Lopes]]></itunes:name></itunes:owner><itunes:author><![CDATA[Daniel Lopes]]></itunes:author><googleplay:owner><![CDATA[daniellopes@substack.com]]></googleplay:owner><googleplay:email><![CDATA[daniellopes@substack.com]]></googleplay:email><googleplay:author><![CDATA[Daniel Lopes]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[How to define your Ideal Customer Profile (ICP)]]></title><description><![CDATA[An in-depth study guide to ideal customer profiles: what they are, what they aren't, and how to build one.]]></description><link>https://journal.daniellopes.dev/p/defining-your-ideal-customer-profile</link><guid isPermaLink="false">https://journal.daniellopes.dev/p/defining-your-ideal-customer-profile</guid><dc:creator><![CDATA[Daniel Lopes]]></dc:creator><pubDate>Mon, 24 Aug 2026 21:14:10 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!XMs4!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb566d0d9-f680-4a94-b62d-23c1e521a3a8_634x355.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!XMs4!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb566d0d9-f680-4a94-b62d-23c1e521a3a8_634x355.webp" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!XMs4!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb566d0d9-f680-4a94-b62d-23c1e521a3a8_634x355.webp 424w, https://substackcdn.com/image/fetch/$s_!XMs4!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb566d0d9-f680-4a94-b62d-23c1e521a3a8_634x355.webp 848w, https://substackcdn.com/image/fetch/$s_!XMs4!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb566d0d9-f680-4a94-b62d-23c1e521a3a8_634x355.webp 1272w, https://substackcdn.com/image/fetch/$s_!XMs4!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb566d0d9-f680-4a94-b62d-23c1e521a3a8_634x355.webp 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!XMs4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb566d0d9-f680-4a94-b62d-23c1e521a3a8_634x355.webp" width="728" height="407.6340694006309" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b566d0d9-f680-4a94-b62d-23c1e521a3a8_634x355.webp&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:355,&quot;width&quot;:634,&quot;resizeWidth&quot;:728,&quot;bytes&quot;:8640,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/webp&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://journal.daniellopes.dev/i/212372039?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76be9c2f-d9a1-4460-afc7-6e6e14033029_1376x768.webp&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:&quot;center&quot;,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!XMs4!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb566d0d9-f680-4a94-b62d-23c1e521a3a8_634x355.webp 424w, https://substackcdn.com/image/fetch/$s_!XMs4!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb566d0d9-f680-4a94-b62d-23c1e521a3a8_634x355.webp 848w, https://substackcdn.com/image/fetch/$s_!XMs4!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb566d0d9-f680-4a94-b62d-23c1e521a3a8_634x355.webp 1272w, https://substackcdn.com/image/fetch/$s_!XMs4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb566d0d9-f680-4a94-b62d-23c1e521a3a8_634x355.webp 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p>The standard definition: an ideal customer profile (ICP) is an account-level description of the companies you are best at winning, serving, retaining and expanding. It is a short list of firmographic and technographic criteria, plus explicit disqualifiers, scored and tiered in the CRM.</p><p>An ICP describes companies rather than people. A buyer persona is the person inside the account, <a href="https://www.techtarget.com/searchcustomerexperience/definition/TAM-SAM-SOM">TAM/SAM/SOM</a> are market-size estimates in dollars, and an ABM target list is the named accounts you are working right now.</p><p>That definition is correct, and it produces some pretty useless docs. Sort your customers by industry and headcount and you get a profile that describes who they <em>are</em> while saying nothing about why they bought.</p><p>We wrote ours for the GrowthOS launch and now 2 months in revisited focused on the way round, starting from the job. <a href="https://www.library.hbs.edu/working-knowledge/what-customers-want-from-your-products">Christensen</a>: &#8220;The job, not the customer, is the fundamental unit of analysis.&#8221; Bob Moesta&#8217;s version changes what you do on a Tuesday: demand starts at a <a href="https://therewiredgroup.com/learn/demand-side-sales-101-stop-selling-and-help-your-customers-make-progress/">struggling moment</a> and &#8220;it&#8217;s not an imagined customer or persona, it&#8217;s real buyers.&#8221;</p><p>So the first question is not what kind of company buys this. It is which organizations hit the struggling moment this product resolves, what progress they are trying to make, and what they are hiring today instead. Firmographics come back as filters on that answer, never as the explanation for it.</p><p>The other half of a real ICP is that it is enforceable: an SDR can disqualify an account against it, RevOps can score and route on it, and it gets reviewed monthly against closed-won data.</p><h2>Revisiting our ICP</h2><p>We wrote our ICP doc before GrowthOS launched in June 2026. It was a hypothesis with a template around it: which companies the platform would be structurally best at winning, extrapolated from work we had been doing for clients by hand. The first paid clients of the platform have since converted onto annual plans, which is the first evidence in the exercise that isn&#8217;t a guess, so we went back to the doc.</p><p>Before touching it, I created this study guide for myself, but I&#8217;m sharing it here since it might be a helpful resource.</p><p>A caveat on the numbers: they come from different years, samples and definitions, so several of them disagree. Use them as shape, not as truth.</p><p></p><div><hr></div><h2>Audio version</h2><p>Here&#8217;s a computer generated audio version of this guide adapted for listening</p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;c8251a5e-f9d5-485d-bff3-d3fa4765a0b0&quot;,&quot;duration&quot;:2370.7952,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><div><hr></div><p></p><h2>What an ICP is, and what it isn&#8217;t (TAM, target lists, personas)</h2><p><a href="https://www.revopscoop.com/webinar-series/finding-and-unleashing-the-power-of-your-icp-across-gtm">RevOps Co-op</a> defines an ICP through four operational questions: who will buy, who will purchase smoothly and on time, who can be implemented and serviced, and who will renew, refer and expand.</p><p>Only the first is a sales question. An ICP built from &#8220;who signs&#8221; systematically overweights accounts that close and churn, which is why retention and expansion data belong in the derivation rather than in a CS dashboard.</p><p>The definitions worth having in front of you. <a href="https://offers.hubspot.com/ideal-customer-profile-icp">HubSpot</a> grounds it in data: an ICP is &#8220;based on company level firmographic and technographic data points (like employee size, technologies used, industry, and more).&#8221; <a href="https://review.firstround.com/the-most-common-go-to-market-questions-from-founders/">First Round Review</a> adds the temporal part: &#8220;a detailed description of the perfect customer (in the case of B2B, that means company)&#8221; and &#8220;a living definition that needs to be revisited frequently.&#8221; <a href="https://www.saastr.com/saastr-podcast-457-and-video-building-your-ideal-customer-profile/">SaaStr</a> raises the stakes: &#8220;Your ICP strategy is the basis for your entire company&#8217;s strategy.&#8221;</p><p>Four layers, four different questions:</p><ul><li><p><strong>TAM/SAM/SOM</strong> works at the market aggregate. How large is the opportunity? The output is a dollar figure.</p></li><li><p><strong>The ICP</strong> works at the account level. Which <em>types</em> of companies fit best? The output is attribute criteria and a scoring model.</p></li><li><p><strong>An ABM target account list</strong> works at the named-account level. Which specific companies are we pursuing now? The output is a prioritized list of names.</p></li><li><p><strong>A buyer persona</strong> works at the individual level. Who inside those companies do we engage, and how? The output is a role, goal and pain profile.</p></li></ul><p>The sequence runs: size the market, define ICP attributes, score the addressable universe, apply capacity and territory filters to get the named list, then map the buying committee with personas.</p><p><a href="https://clearbit.com/resources/books/ideal-customer-profile/icp-go-to-market-strategy">Clearbit</a> draws the market-sizing line cleanly: &#8220;TAM, SAM, and SOM identify market potential and are represented by a dollar value. Your ICP takes that a step further and serves as a definition of the companies that are the best fit for your business.&#8221; Clay&#8217;s <a href="https://www.clay.com/guides/total-addressable-market">version</a>: &#8220;every ICP account is in your TAM, but most TAM accounts are not in your ICP.&#8221;</p><p>On personas, <a href="https://blog.hubspot.com/customers/ideal-customer-profiles-and-buyer-personas-are-they-different">HubSpot</a> gives the operating split: &#8220;Think of your ICP as your pre-qualification filter and buyer personas as your personalization guide.&#8221; <a href="https://www.forrester.com/blogs/saying-goodbye-to-mqls-accounts-buying-groups-opportunities-oh-my-how-is-it-all-connected/">Forrester</a> adds the complication that makes personas insufficient on their own: the same VP of HR can sit in several buying groups and play a different role in each. The five common roles are champion, influencer, decision-maker, user and ratifier.</p><p>An account can be a perfect ICP match and still sit outside the active target list on capacity or timing, which is why <a href="https://knowledge.hubspot.com/branding/get-started-with-account-based-marketing-in-hubspot">HubSpot&#8217;s ABM system</a> tracks &#8220;target account&#8221; and &#8220;ICP tier&#8221; as two separate properties, Tier 1 being &#8220;a great fit&#8221; and Tier 3 &#8220;acceptable, but low priority.&#8221;</p><p>A fourth distinction is between ICP and IPP. Force Management <a href="https://meddicc.com/resources/storytime-icp-ipp">draws the line</a> &#8220;ideal customer profile does not necessarily equal ideal prospect profile.&#8221; A prestigious account can match the profile and still be a bad near-term prospect on stakeholder complexity or contract timing.</p><p><a href="https://www.lennysnewsletter.com/p/lessons-learned-from-a-startup-that">Jake Fuentes at Cascade</a> gives the test for whether a candidate segment is real: &#8220;An ICP must be a single market segment: a group of people for whom the value of solving a problem is roughly the same, and who can be reached in roughly the same way.&#8221; Equal value and equal reachability, both necessary. <a href="https://openviewpartners.com/blog/resegment-your-market/">OpenView</a> arrives at the same test independently: a good segment &#8220;gets value in the same way and buys in the same way.&#8221;</p><p>Meka Asonye at <a href="https://review.firstround.com/this-gtm-leader-turned-investor-crowdsources-early-lessons-from-stripe-figma-and-more/">First Round</a> shows the difference between a vague segment and a usable one. Bad: &#8220;Series B technology companies.&#8221; Good: &#8220;companies who are experiencing X, who look like Y, who have previously tried these three solutions and need the product to do A, B, and C.&#8221;</p><h2>Fit vs intent: why an ICP needs two scores</h2><p>I&#8217;d install a fit-versus-intent model first. <a href="https://www.clay.com/guides/ideal-customer-profile">Clay</a> defines fit as whether a company <em>should</em> buy from you, derived from stable attributes like size and stack. Intent is whether it&#8217;s looking right now, derived from recent signals like funding or hiring.</p><p>A high-fit, low-intent account is a nurture target. A high-intent, low-fit account is a distraction.</p><p>Score the two axes separately so you can treat them differently, then combine at routing. Fit is the eligibility gate; intent and timing set the tier. <a href="https://bombora.com/blog/from-signals-to-pipeline-7-lessons-for-delivering-efficient-growth/">Bombora</a> puts it from the data side: only a small portion of your ICP is in market at any time, and intent data exists &#8220;not to define your ICP, but to reveal which accounts are actively researching and should be prioritized now.&#8221;</p><p>The compelling event is why a static firmographic profile underperforms a signal-laden one. <a href="https://revopsmasters.com/category/data-analysis/win-loss-analysis/">RevOps Masters</a> reports its win/loss result: &#8220;The single most predictive factor in win/loss outcomes is whether the buyer had an identified event or deadline driving the purchase. Deals with a compelling event close at 3-4&#215; the rate of those without one.&#8221;</p><p><a href="https://clearbit.com/blog/how-to-use-webpage-intent">Clearbit&#8217;s</a> routing rule shows what combining the axes looks like in practice: &#8220;High-intent visitors should speak to sales right away if they have high fit. Low-intent visitors can be added to an ad retargeting campaign, email nurture sequence.&#8221; Their threshold example: an account that visited at least three relevant pages in a month, whose fit score qualified, got routed to the BDR team.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!BhYX!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1d38ef0-d7cc-4346-bc60-00335374bb62_1448x1086.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!BhYX!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1d38ef0-d7cc-4346-bc60-00335374bb62_1448x1086.png 424w, https://substackcdn.com/image/fetch/$s_!BhYX!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1d38ef0-d7cc-4346-bc60-00335374bb62_1448x1086.png 848w, https://substackcdn.com/image/fetch/$s_!BhYX!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1d38ef0-d7cc-4346-bc60-00335374bb62_1448x1086.png 1272w, https://substackcdn.com/image/fetch/$s_!BhYX!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1d38ef0-d7cc-4346-bc60-00335374bb62_1448x1086.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!BhYX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1d38ef0-d7cc-4346-bc60-00335374bb62_1448x1086.png" width="728" height="546" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f1d38ef0-d7cc-4346-bc60-00335374bb62_1448x1086.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:1086,&quot;width&quot;:1448,&quot;resizeWidth&quot;:728,&quot;bytes&quot;:1944801,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://journal.daniellopes.dev/i/212372039?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1d38ef0-d7cc-4346-bc60-00335374bb62_1448x1086.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:&quot;center&quot;,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!BhYX!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1d38ef0-d7cc-4346-bc60-00335374bb62_1448x1086.png 424w, https://substackcdn.com/image/fetch/$s_!BhYX!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1d38ef0-d7cc-4346-bc60-00335374bb62_1448x1086.png 848w, https://substackcdn.com/image/fetch/$s_!BhYX!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1d38ef0-d7cc-4346-bc60-00335374bb62_1448x1086.png 1272w, https://substackcdn.com/image/fetch/$s_!BhYX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1d38ef0-d7cc-4346-bc60-00335374bb62_1448x1086.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><h2>Which attributes belong in an ICP?</h2><p>Four attribute families matter, and most bad ICPs stop at the first.</p><ul><li><p><strong>Firmographic.</strong> The <a href="https://brick.work/blog/the-revops-approach-to-defining-your-icp">standard set</a>: industry, company size, revenue range, employee count, geography and business model, plus <a href="https://abmatic.ai/blog/what-is-account-fit-score-for-revops">ownership type</a>. <a href="https://www.bvp.com/atlas/how-to-segment-your-customer-base-for-more-precise-pricing-and-packaging">Bessemer&#8217;s bands</a>: Commercial 1-500 employees, Mid-market 501-1,000, Enterprise 1,000+, with revenue bands of $0-1M, $1.1-10M and $10.1M+.</p></li><li><p><strong>Technographic.</strong> <a href="https://pipeline.zoominfo.com/sales/technographic-targeting">What they run</a>: &#8220;which CRM they run, what marketing tools they rely on, where they host their infrastructure, and what sales platforms their reps use every day.&#8221; Two mid-market SaaS companies &#8220;might look identical on paper, but if one uses Salesforce with a modern tech stack and the other runs a legacy CRM with no API access, your approach should be completely different.&#8221; <a href="https://hginsights.com/product/rgi-fabric/">HG Insights</a> goes further, measuring behind-the-firewall usage intensity and maturity, and separating Problem Aware, Solution Aware and Product Aware stages.</p></li><li><p><strong>Behavioral.</strong> <a href="https://brick.work/blog/the-revops-approach-to-defining-your-icp">Buying signals</a>: content consumption, website engagement, event attendance, search intent. What separates companies that fit your ICP in theory from ones actively buying. In product-led motions this is where PQLs live, converting at <a href="https://openviewpartners.com/blog/your-guide-to-product-qualified-leads-pqls/">15-30%</a> on signals like usage frequency, adoption of high-value features, usage growth week over week, and multi-product usage.</p></li><li><p><strong>Psychographic.</strong> How the organization decides. One <a href="https://customerthink.com/no-fit-no-deal-why-icp-fit-must-be-the-first-thing-you-qualify-in-complex-b2b-sales/">list worth stealing</a> covers &#8220;appetite for innovation, willingness to buy best-of-breed, attitude to vendors, decision-making style.&#8221; The <a href="https://www.thevxgroup.com/insights/b2b-enterprise-target-profile-criteria/">pace difference</a> matters too: &#8220;Some decisions require consensus across a large leadership team. Others sit with a single executive who acts quickly.&#8221; Lenny Rachitsky lists a company&#8217;s <a href="https://www.lennysnewsletter.com/p/how-to-identify-your-ideal-customer">&#8220;way of working&#8221;</a>, design-driven or operationally heavy, as an explicit field.</p></li></ul><p>Prefer operational signals to generic firmographics wherever you can get them. <a href="https://review.firstround.com/the-most-common-go-to-market-questions-from-founders/">First Round&#8217;s</a> example is the cleanest illustration: instead of targeting companies with more than 500 employees, target &#8220;companies with more than 20 open, remote roles on LinkedIn. That&#8217;s a sharper ICP.&#8221; Same for pain: &#8220;It&#8217;s not enough to know the pain the prospect has, you want to deeply understand the impact of that pain.&#8221;</p><p><a href="https://www.bvp.com/atlas/a-b2b-founders-guide-to-generating-demand-from-scratch">Bessemer&#8217;s five-factor needs framework</a>, credited to Allyson Letteri, is the best short prompt list I&#8217;ve found for the situational half:</p><p><strong>Pains:</strong> what pressing problems can your solution solve? <strong>Gains:</strong> what goals or desired outcomes drive your customer? <strong>Shifts:</strong> what company changes would make them open to new solutions? <strong>Blockers:</strong> what objections or misconceptions might hinder adoption? <strong>Motivators:</strong> what would urge them to move forward, ROI or testimonials or something else?</p><p>Shifts is the underused row. Common ones are &#8220;compliance mandates, a crisis or breach, new executives joining the team, or even when the team outgrows old systems.&#8221;</p><p>Product usage deserves its own note if you have a free tier. <a href="https://openviewpartners.com/blog/your-guide-to-product-led-sales/">OpenView</a> reports that Figma defined activation as &#8220;a user collaborates with other users in their first week&#8221; and modeled around 10 data points where &#8220;when two or more of these were triggered, there was a high likelihood for the account to upgrade.&#8221; A concrete multi-user trigger from the same playbook: <a href="https://openviewpartners.com/blog/your-guide-to-product-qualified-leads-pqls/">when three or</a> more users at the same company reach a high usage threshold, email the manager.</p><p>The <a href="https://therewiredgroup.com/learn/demand-side-sales-101-stop-selling-and-help-your-customers-make-progress/">jobs-to-be-done</a> lens turns a tidy attribute list into a usable one. <a href="https://anthonyulwick.com/jobs-to-be-done/">Tony Ulwick</a> separates the job from the outcome, &#8220;a metric the customer uses to measure success&#8221;, which lets you <a href="https://anthonyulwick.com/2016/10/25/jobs-to-be-done-from-theory-to-practice/">cluster accounts</a> by which desired outcomes are underserved and define segments that cut across industry and size bands. <a href="https://openviewpartners.com/blog/market-segmentation-hypothesis/">OpenView</a> warns that conventional segmentation &#8220;can be severely deficient because it is an arbitrarily imposed view of the market,&#8221; and every criterion needs &#8220;a clear rationale as to why the particular criterion will impact or differentiate the needs or buying behavior of targets.&#8221;</p><p>Looker&#8217;s 2013-2015 ICP led with the job: &#8220;technical data teams, not end users or business analysts, who were starting to adopt cloud with large data sizes and complex analytical requirements AND the need to support a larger base of less technical end users.&#8221; Company size, 50-400 employees, <a href="https://www.lennysnewsletter.com/p/how-to-identify-your-ideal-customer">appears only as a supporting filter</a> and never as the explanation for demand.</p><h3>How many attributes, and how narrow</h3><p>Rachitsky collected the initial ICPs of more than a dozen B2B startups and <a href="https://www.lennysnewsletter.com/p/how-to-identify-your-ideal-customer">found</a> that &#8220;everyone landed on at least <em>three</em> attributes to describe their ICP. Some had more, but no one had fewer.&#8221; His instruction is to get &#8220;super-specific and super-narrow. Almost comically narrow.&#8221;</p><p>The receipts are the useful part:</p><ul><li><p><strong>Gusto</strong> <a href="https://www.lennysnewsletter.com/p/how-to-identify-your-ideal-customer">started with</a> companies of five or fewer employees, in California, offering no benefits, salaried employees only, no other deductions, and willing to be paid eight days after running payroll.</p></li><li><p><strong>Gong</strong> picked three: selling in the US in English, selling via video conferencing, and selling software worth $1,000 to $100,000, &#8220;because beyond $100k, we assumed it was going to be a different sales cycle, and less than $1,000, it would be too transactional.&#8221; That left <a href="https://www.lennysnewsletter.com/p/how-to-identify-your-ideal-customer">roughly 5,000 companies worldwide</a>.</p></li><li><p><strong>Snyk</strong> <a href="https://www.lennysnewsletter.com/p/how-to-identify-your-ideal-customer">went depth-first</a>: &#8220;a developer building with Node.js who was very security-conscious.&#8221;</p></li><li><p><strong>Canva</strong> <a href="https://www.lennysnewsletter.com/p/how-to-identify-your-ideal-customer">found theirs six months in</a>, watching who got excited: social media managers and bloggers, &#8220;especially freelancers, who were building their own social media management business.&#8221;</p></li></ul><p>At the other end, keep the filter to <a href="https://hyperspect.ai/blog/icp-definition-framework">4-7 attributes</a>. More than 8-10 filtering dimensions and it is over-specified, fitting noise, and no longer usable by an SDR in real time.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!j6TE!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d034d68-1f73-41ea-9cb9-fa8c28919f65_1536x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!j6TE!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d034d68-1f73-41ea-9cb9-fa8c28919f65_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!j6TE!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d034d68-1f73-41ea-9cb9-fa8c28919f65_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!j6TE!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d034d68-1f73-41ea-9cb9-fa8c28919f65_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!j6TE!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d034d68-1f73-41ea-9cb9-fa8c28919f65_1536x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!j6TE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d034d68-1f73-41ea-9cb9-fa8c28919f65_1536x1024.png" width="1456" height="971" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9d034d68-1f73-41ea-9cb9-fa8c28919f65_1536x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:971,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1405437,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://journal.daniellopes.dev/i/212372039?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d034d68-1f73-41ea-9cb9-fa8c28919f65_1536x1024.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!j6TE!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d034d68-1f73-41ea-9cb9-fa8c28919f65_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!j6TE!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d034d68-1f73-41ea-9cb9-fa8c28919f65_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!j6TE!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d034d68-1f73-41ea-9cb9-fa8c28919f65_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!j6TE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d034d68-1f73-41ea-9cb9-fa8c28919f65_1536x1024.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><h2>Five frameworks for choosing a segment</h2><p>Each framework contributes a different narrowing mechanism. You don&#8217;t need all five, but you should know which one you&#8217;re using.</p><p>In one line each: Moore picks the first segment by use-case urgency and reference community. Blank validates that a specific org type and buyer will actually purchase. Lean Analytics replaces aggregate counts with cohort metrics. MEDDPICC tests reality inside an account and aggregates into buyability patterns. Top-10 reverse engineering derives the profile from realized outcomes.</p><p><strong>Moore.</strong> The transition that matters is early adopters to <a href="https://geoffreyamoore.com/book/crossing-the-chasm/">pragmatists</a> who &#8220;want to see it proven out first, specifically in use cases that they themselves have and with customers they know and can reference.&#8221; A market is defined partly by <a href="https://archive.org/stream/crossingthechasm_202002/Crossing%20the%20Chasm_djvu.txt">reference behavior</a> customers must &#8220;reference each other when making a buying decision.&#8221; Choose the first segment on problem <a href="https://fredlybrand.com/2019/08/17/moores-crossing-the-chasm-ch-03-the-d-day-analogy/">severity</a> rather than size,: &#8220;The size of the first pin is not the issue, but the economic value of the problem it fixes is. The more serious the problem, the faster the target niche will pull you out of the chasm.&#8221; The ICP has to encode the <a href="https://bradenkelley.com/2023/01/winning-in-a-downturn-requires-delivering-the-whole-product/">whole product</a>, &#8220;the complete set of products and services needed to fulfill the compelling reason to buy,&#8221; which doubles as a test of whether you can actually serve the segment. Expansion then follows the bowling alley: target a <a href="https://fredlybrand.com/2019/08/17/moores-crossing-the-chasm-ch-03-the-d-day-analogy/">connected segment</a> that &#8220;by virtue of its other connections, creates an entry point into a larger segment.&#8221;</p><p><strong>Blank.</strong> <a href="https://steveblank.com/2009/09/17/the-path-of-warriors-and-winners/">Customer Development</a> runs discovery, validation, creation, company building. The earlyvangelist five criteria are the <a href="https://steveblank.com/2010/03/04/perfection-by-subtraction-the-minimum-feature-set/">pre-ICP filter</a>: &#8220;They have a problem. They understand they have a problem. They are actively searching for a solution and have a timetable for finding it. The problem is painful enough that they have cobbled together an interim solution. They have, or can quickly acquire, dollars to purchase the product.&#8221; He also advises <a href="https://steveblank.com/2009/07/30/hes-only-in-field-service/">going after</a> companies that &#8220;aren&#8217;t the market leaders in their industries, but are fighting hard to get there,&#8221; then finding the internal evangelist who wants the competitive advantage. The <a href="https://steveblank.com/2009/11/02/lean-startups-aren%E2%80%99t-cheap-startups/">validated sales model</a> has to answer who influences, who recommends, who decides, who pays, where the budget sits, what acquisition costs, and how long a sale takes.</p><p><strong>Lean Analytics.</strong> Cohort discipline instead of <a href="https://jomrcr.svbtle.com/notes-lean-analytics">aggregate counts</a> since &#8220;you can compare cohorts against one another to see if, on the whole, key metrics are getting better over time.&#8221; The <a href="https://leananalyticsbook.com/one-metric-that-matters/">OMTM</a> is stage-dependent and temporary, and in <a href="https://leananalyticsbook.com/quantitative-interviews-the-importance-of-scoring-customer-feedback/">interviews</a> you &#8220;look for a subset of scores that spike; that&#8217;s your early-adopter customer segment.&#8221; <a href="https://www.demandrevenue.com/ideal-customer-profile-b2b-cmo/">Three cohorts, three questions</a>: acquisition and win/loss (&#8221;can we get them?&#8221;), retention and GRR (&#8221;do they stay?&#8221;), expansion and NRR (&#8221;do they grow?&#8221;). The method needs an <a href="https://leadanic.com/blog/ideal-customer-profile-b2b/">overfit warning</a>: &#8220;if accounts that match your candidate ICP also churned at the highest rate, you have over-fit on a non-causal pattern and need to add an exclusion criterion.&#8221;</p><p><strong>MEDDIC/MEDDPICC.</strong> <a href="https://meddicc.com/meddpicc-sales-methodology-and-process">Metrics, Economic buyer, Decision</a> criteria, Decision process, Paper process, Identify pain, Champion, Competition, originally developed in 1996 by Dick Dunkel at PTC, with <a href="https://arpedio.com/resources/guides/meddpicc">Paper Process and Competition added later</a>. MEDDPICC contributes the feedback loop. Aggregate outcomes across won, lost, stalled and no-decision deals, tagged by account attributes, and you learn which characteristics predict buyability, cycle time and commercial success rather than theoretical fit.</p><p><strong>Top-10 reverse engineering.</strong> Derive the profile from realized outcomes. <a href="https://www.saastr.com/saastr-podcast-457-and-video-building-your-ideal-customer-profile/">SaaStr&#8217;s</a> questions for your best deals: &#8220;How easy is it to close these top deals? How simple was it to set your customer up with onboarding and implementation? How sticky is your product?&#8221; A <a href="https://yourlastagency.com/how-to-determine-ideal-customer-profile-icp/">working version</a> analyzes &#8220;10 to 20 best existing customers across revenue contribution, retention rate, sales cycle length, and product fit.&#8221; <a href="https://allstonlabs.com/library/icp/closed-won-deconstruction">Allston Labs</a> is the most rigorous: capture three layers per customer, &#8220;firmographic (who they are), behavioral (how they bought), and deal-shape (the buying committee that signed)... including the nulls, the distribution of nulls is itself a signal.&#8221; Weight the expansion cohort 3-5&#215; because repeat purchase reveals organizational fit as well as product fit, treat closed-lost as &#8220;the empirical control group,&#8221; and note their headline claim: &#8220;the single highest-confidence ICP indicator is per-customer ACV growth at 12 months.&#8221;</p><h2>How do you build an ICP from data?</h2><p>Six analyses, in the order to run them.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!pJpi!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2c1e59c-eb25-4dcc-9fcf-4625dd9558eb_1536x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!pJpi!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2c1e59c-eb25-4dcc-9fcf-4625dd9558eb_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!pJpi!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2c1e59c-eb25-4dcc-9fcf-4625dd9558eb_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!pJpi!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2c1e59c-eb25-4dcc-9fcf-4625dd9558eb_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!pJpi!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2c1e59c-eb25-4dcc-9fcf-4625dd9558eb_1536x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!pJpi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2c1e59c-eb25-4dcc-9fcf-4625dd9558eb_1536x1024.png" width="1456" height="971" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a2c1e59c-eb25-4dcc-9fcf-4625dd9558eb_1536x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:971,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1253529,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://journal.daniellopes.dev/i/212372039?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2c1e59c-eb25-4dcc-9fcf-4625dd9558eb_1536x1024.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!pJpi!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2c1e59c-eb25-4dcc-9fcf-4625dd9558eb_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!pJpi!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2c1e59c-eb25-4dcc-9fcf-4625dd9558eb_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!pJpi!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2c1e59c-eb25-4dcc-9fcf-4625dd9558eb_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!pJpi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2c1e59c-eb25-4dcc-9fcf-4625dd9558eb_1536x1024.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><h3>1. Closed-won and closed-lost</h3><p>Build a joinable dataset across six layers: opportunity, account, contact, source and campaign, product and use case, and post-sale retention. <a href="https://foundryops.io/guides/icp-persona-model-hubspot-exports">Separate new-logo, expansion</a> and renewal cohorts before analyzing. <a href="https://revopsmasters.com/category/data-analysis/win-loss-analysis/">Use a two-level loss taxonomy</a>: primary as competitive, no decision, price and budget, or product gap; secondary as feature depth, integration ecosystem, implementation timeline.</p><p>Pull the last 12-24 months. No-decision outcomes are <a href="https://revopsmasters.com/category/data-analysis/win-loss-analysis/">25-40% of closed-lost deals</a> on their own and should never be merged into competitor or price losses.</p><p>How much data you need before believing the pattern: <a href="https://allstonlabs.com/library/icp/closed-won-deconstruction">5-7 closed-won deals</a> support a provisional hypothesis and nothing more, <a href="https://gtmepulse.com/insights/icp-definition-framework/">30 closed-won</a> is a stronger first-pass minimum, and <a href="https://revopsmasters.com/category/data-analysis/win-loss-analysis/">50 combined closed deals</a> supports general win/loss pattern analysis.</p><p>Two behavioral signals worth pulling in the same query: hiring activity is associated with a <a href="https://gtmepulse.com/insights/icp-definition-framework/">2.4&#215; conversion lift</a>, and funding events indicate a 3-6 month timing window. And triangulate rather than trusting one source: <a href="https://revopsmasters.com/category/data-analysis/win-loss-analysis/">RevOps Masters</a> recommends CRM loss reasons, rep debrief surveys and buyer interviews together, because rep-entered reasons measure perception.</p><p>A defensible scoring starting point, if you want one before you have enough data for a model: a <a href="https://gtmepulse.com/insights/icp-definition-framework/">0-100 scorecard</a> weighted firmographic fit 30, technographic fit 25, behavioral signals 25, deal potential 20.</p><h3>2. Win rate and cycle length by segment</h3><p>Never report blended. The example that makes it obvious: &#8220;A 24% aggregate win rate breaking down to 41% for SMB inbound and 9% for enterprise outbound tells you everything.&#8221;</p><p>The formulas, so the segmentation happens before the math: win rate by count is won deals divided by won plus comparable closed-lost, and <a href="https://blog.hubspot.com/sales/b2b-sales-metrics">sales velocity</a> is opportunities &#215; deal value &#215; win rate &#247; cycle length. Segment by market size first, then calculate.</p><p>Across 4.2M opportunities at 530 companies and $54B of revenue, Ebsta and Pavilion found top performers had <a href="https://benchmarks.ebsta.com/hubfs/V3%202025%20Benchmark%20Report/gtm_benchmarks_digital_report.pdf?hsLang=en">42% shorter cycles, 76%</a> higher ACV and 43% higher win rates than average. Early decision-maker involvement in the first two stages <a href="https://benchmarks.ebsta.com/hubfs/V3%202025%20Benchmark%20Report/gtm_benchmarks_digital_report.pdf?hsLang=en">lifted win rates 55%</a>, high-intent accounts closed at <a href="https://www.ebsta.com/wp-content/uploads/2024/02/B2B-Sales-Benchmarks-2024_.pdf">3.4&#215; velocity</a>, and top performers were <a href="https://www.joinpavilion.com/hubfs/Ebsta%20x%20Pavilion%202025%20GTM%20Benchmarks%20Report.pdf">24% more likely</a> to disqualify non-ICP deals early. For orientation, average B2B win rates run <a href="https://revenuegrid.com/blog/how-to-build-a-sales-analytics-practice/">15-25% with mid-market cycles of 30-90 days</a>, and lost deals take <a href="https://19965450.fs1.hubspotusercontent-na2.net/hubfs/19965450/2026%20Benchmarks%20Report%20Assets/Fullcast_Pavillion-2026-GTM-Benchmark%20Report.pdf">2.0&#215; longer</a> than won ones.</p><p>One data-quality caveat before you trust any of your own numbers: Clari Labs, across 10M opportunities at 121 global enterprises, found <a href="https://www.clari.com/downloads/state-of-enterprise-revenue-clari-labs-benchmark-report-2025/">98% of companies</a> fail to track closed-lost reasons consistently.</p><h3>3. Unit economics by segment</h3><p>Read gross-margin-adjusted CAC payback together with net dollar retention rather than alone, since <a href="https://openviewpartners.com/blog/how-do-you-stack-up-2022-saas-benchmarks/">a segment with</a> short payback but poor retention is misleading. The <a href="https://www.joinpavilion.com/hubfs/2024%20B2B%20SaaS%20Performance%20Metrics%20Benchmarks%20Report.pdf">formula</a>: sales and marketing spend to acquire new customers &#247; (contracted new ARR &#215; gross margin) &#215; 12.</p><p><a href="https://www.bvp.com/atlas/state-of-the-cloud-2023">Bessemer grades it</a> good at 12-18 months, better at 6-12, best at 0-6, with <a href="https://www.bvp.com/atlas/seven-saas-resiliency-lessons-for-doing-business-in-a-volatile-market">segment targets in favorable conditions</a> of SMB under 12, mid-market under 18, enterprise under 24.</p><p><a href="https://www.cfodesk.co.il/wp-content/uploads/2023/09/OpenView-SaaS-Benchmarks-Report_2022.pdf">OpenView measured it</a>:</p><p>by target customer, as good (50th percentile) against great (80th): under 20 employees, 9 months against 2; SMB at 20-100 employees, 7 against 4; midmarket at 101-1,000, 14 against 7; enterprise above 1,000, 14 against 9.</p><p><a href="https://www.key.com/content/dam/kco/documents/businesses___institutions/2024_kbcm_sapphire_saas_survey.pdf">KeyBanc&#8217;s 2024 survey</a> puts fully-loaded payback at 25 months in 2022, 21 in 2023 and 20 estimated for 2024. These figures disagree because the years, samples, ARR scales and definitions differ. Shape, not truth.</p><h3>4. Retention cohorts</h3><p>GRR is the stickiness check, NRR the expansion check, and a strong NRR can hide widespread churn behind a few large expansions. The <a href="https://chartmogul.com/saas-metrics/customer-churn/">formulas</a>: NRR includes expansion and reactivation and can exceed 100%; <a href="https://chartmogul.com/reports/saas-benchmarks-report/">GRR excludes expansion and caps at 100%</a>.</p><p>Benchmarks worth arguing with: <a href="https://www.bvp.com/atlas/state-of-the-cloud-2023">Bessemer&#8217;s good/better/best</a> is NRR 100/110/120%+ with logo retention above 85/90/95%; best-in-class B2B NRR sits at <a href="https://chartmogul.com/reports/saas-benchmarks-report/">110-125%</a> with <a href="https://chartmogul.com/saas-metrics/customer-churn/">median monthly churn of 3.7%</a> for $1-3M ARR companies; <a href="https://www.iconiqcapital.com/growth/reports/2025-state-of-software">ICONIQ&#8217;s 2025 report</a> has software NDR settling around 110-120%; and <a href="https://openviewpartners.com/2023-saas-benchmarks-report/">OpenView&#8217;s 2023 data</a> shows PLG companies at 105% NDR against 98% for non-PLG.</p><p>The number that justifies the whole exercise, from <a href="https://openviewpartners.com/blog/churn-customer-success-problem/">OpenView</a>: &#8220;annual retention rates can vary from 50% to 90% across different customer types for the same product.&#8221;</p><p>In <a href="https://clearbit.com/resources/books/ideal-customer-profile/redefining-icp">Clearbit&#8217;s</a> worked example, ~86% of long-term revenue came from ~18% of leads entering the funnel, and they narrowed the ICP accordingly.</p><h3>5. Usage and time-to-value</h3><p>Median SaaS <a href="https://www.lennysnewsletter.com/p/what-is-a-good-activation-rate">activation</a> is 30%, average 36%, and activated users should retain at 2&#215; non-activated. For B2B, activation typically takes <a href="https://openviewpartners.com/blog/the-definitive-guide-product-analytics-for-product-led-growth/">two to three weeks</a> rather than minutes. <a href="https://openviewpartners.com/blog/how-similarweb-grew-to-190m-revenue-run-rate-and-beyond/">Similarweb scores PQLs</a> on two factors, ICP attributes (company size, role, use intent) and usage behavior (frequency and breadth), combining them to set engagement level and which product to sell.</p><p>Strong-fit usage looks like fast time to value, high activation against matched non-ICP cohorts, repeated use of the core workflow, adoption of the differentiating feature, multiple active users or departments, and usage rising over time.</p><p>Weak fit looks like signup without ever reaching the aha, shallow single-feature or one-off use, low account breadth, frequency declining after the trial, a high support and onboarding burden, and no expansion path.</p><h3>6. Interviews</h3><p>Quantitative data alone misses the mechanism, and there is a number for how badly. <a href="https://www.clozd.com/solutions/win-loss-analysis-software">Clozd</a> reports that buyer and seller reasons for closed-lost deals &#8220;only align 15% of the time, meaning 85% of CRM closed-lost data is potentially inaccurate,&#8221; and that roughly 70% of buyers name a different primary competitor than the CRM has. Surveys alone don&#8217;t fix it either: <a href="https://www.clozd.com/blog/win-loss-analysis-why-surveys-alone-wont-cut-it">response rates in</a> some B2B sectors run under 2%.</p><p>The thresholds worth knowing: <a href="https://review.firstround.com/how-to-know-if-your-ideas-the-right-one-a-founders-guide-for-successful-early-stage-customer-discovery/">five to eight conversations</a> for a focused discovery sprint, <a href="https://klue.com/blog/win-loss-analysis-guide">ten similar deals</a> as the minimum cohort to see patterns, and <a href="https://www.clozd.com/blog/how-to-build-a-worldclass-winloss-program-from-scratch">twenty within a segment</a> before making a major strategic change.</p><p>Jason Sippey, formerly VP Product at Twitter, <a href="https://review.firstround.com/the-power-of-interviewing-customers-the-right-way-from-twitters-ex-vp-product/">describes the progression</a>: &#8220;After the first 10, you start to see patterns. After 20, you really understand segmentation of the market. After 30, you have a really good understanding of what you actually need to go build.&#8221; His four questions: do you have this problem, how are you solving it today, how much are you spending to solve it, how does it impact your business.</p><p>For loss interviews specifically, <a href="https://gtmoperations.io/blog/win-loss-analysis-gtm-playbook">GTM Operations&#8217;</a> five questions are better than most scripts: what triggered the search, which vendors made the shortlist and what were the first impressions, rank the top three factors in the decision, was there a moment your opinion of us shifted, and what would have had to be different for the outcome to change.</p><p>Two discipline rules. Buyers should speak <a href="https://klue.com/blog/win-loss-interviews">90% of the time</a>. And the payoff for keeping at it: companies running win-loss for two or more years report an <a href="https://www.clozd.com/solutions/win-loss-analysis-software">84% increase in win rate</a>.</p><p>The same interviews give four qualitative signs that you are closing in on the right segment: a significant jump in conversion rate, a significant jump in enthusiasm, a much stronger desire to act now, and <a href="https://www.lennysnewsletter.com/p/how-to-identify-your-ideal-customer">the nod</a>.</p><p>Sequence: <a href="https://revopsmasters.com/category/data-analysis/win-loss-analysis/">quantitative analysis to</a> find anomalous or attractive cohorts, qualitative interviews to find the mechanism and the language, then a second quantitative test for prevalence and predictive power.</p><h3>Working with a small sample</h3><p>You will almost always be here first. The <a href="https://pulserevops.com/knowledge/q10827">workflow</a> with roughly 12 accounts: pull the top 3 by revenue and top 3 by NPS or NRR, find the shared attributes, and treat the result as a hypothesis you revise quarterly.</p><p>Then borrow four rules from <a href="https://allstonlabs.com/library/icp/closed-won-deconstruction">Allston Labs</a>: use closed-lost as the control group, since attributes that <em>differ</em> between won and lost carry the decision weight; compute a win/loss ratio per attribute, where something appearing in 70% of won and 30% of lost is high signal; weight expansion cohorts 3-5&#215;; and run three to five structured interviews with your most engaged customers.</p><h2>What should an ICP document include?</h2><p>Assembled from <a href="https://discover.gtmplaybook.co/ideal-customer-profile-template-b2b-saas">James Doman-Pipe&#8217;s GTM Playbook template</a>, <a href="https://fullfunnel.io/ideal-customer-profile/">Full Funnel&#8217;s ABM six pillars</a> and <a href="https://www.hubspot.com/hubfs/hubspot-technology-partner-icp-and-jvp-template.pdf">HubSpot&#8217;s partner ICP worksheet</a>.</p><ol><li><p><strong>Header.</strong> Name, owner, last updated, change log. HubSpot&#8217;s is the only one of the three with a change log, and skipping it is how a definition goes stale without anyone noticing.</p></li><li><p><strong>Firmographics.</strong> Industry, employee count, revenue band, geography, business model, <a href="https://hginsights.com/blog/how-to-create-an-ideal-customer-profile-icp/">funding stage and growth rate</a>.</p></li><li><p><strong>Technographics.</strong> Current stack, <a href="https://blog.hubspot.com/sales/account-based-sales">competitive and complementary</a> solutions in use, IT spend and digital maturity.</p></li><li><p><strong>Situational fit.</strong> Pain signal, buying trigger, <a href="https://review.firstround.com/this-gtm-leader-turned-investor-crowdsources-early-lessons-from-stripe-figma-and-more/">current solution</a>, <a href="https://www.hubspot.com/make-my-persona/ideal-customer-profile-template">budget parameters</a>. Doman-Pipe&#8217;s bar for a pain signal is <a href="https://discover.gtmplaybook.co/ideal-customer-profile-template-b2b-saas">observable</a> rather than adjectival,: &#8220;Not &#8216;they have messy data&#8217; but &#8216;their team is manually reconciling data from three tools every Monday morning and it is taking four hours.&#8217; Specific and observable.&#8221;</p></li><li><p><strong>Buying committee.</strong> Economic buyer and what they care about, champion and the pain they feel, <a href="https://www.linkedin.com/posts/azinkevich_icp-abm-b2bmarketing-activity-7141410335445475328-dpE8">influencers, blockers and insiders</a>, and day-to-day users versus buyers.</p></li><li><p><strong>Why we win here.</strong> Two or three outcomes delivered, plus the structural advantage in this segment. If you can&#8217;t name the advantage, this is a segment you can serve rather than one to commit to.</p></li><li><p><strong>Disqualifiers.</strong> Their own section, not the inverse of the positive criteria.</p></li><li><p><strong>CRM fields.</strong> <a href="https://ziellab.com/post/ideal-customer-profile-b2b-guide">Fit score 0-100</a> and ICP tier as properties on the company object, how we find them, owner, last review date.</p></li></ol><h3>Published templates worth copying</h3><ul><li><p><strong><a href="https://a16z.com/framework-define-refine-icp/">a16z&#8217;s nine fields</a>:</strong> company size or revenue range, type of business, geography, industries served, job titles, a definable solvable problem, company-specific attributes, specific technologies used, unique buyer behaviors. With five diagnostic questions: which customers get the most out of the product, what traits do the best share, what objections recur in losses, who is easiest to upsell, and what do competitors&#8217; customers have in common. Their worked example: &#8220;Large global retailers with onsite developer teams that use GitHub; have specific requirements for PII and customer data residence drive vendor decisions; and their cloud usage means they don&#8217;t have on premise requirements.&#8221;</p></li><li><p><strong><a href="https://www.lennysnewsletter.com/p/how-to-identify-your-ideal-customer">Lenny&#8217;s nine fields</a>:</strong> company size, job title, pain point being solved, company&#8217;s unique way of working, specific tech used, type of business, price point, geography, and a unique place the user spends time.</p></li><li><p><strong><a href="https://www.bvp.com/atlas/the-six-ps-of-lean-product-with-kim-caldbeck">Bessemer&#8217;s Six Ps worksheet</a>:</strong> Persona, Problem, Proposition, Product, Positioning, Promotion, with a bar for the persona section I like a lot: if all the criteria are met, the account should buy 80% of the time. Their worked example rejected universities as an ICP because &#8220;the higher education market is incredibly fragmented, insular, has restrictive budgets, and quite political,&#8221; and moved to residency teaching hospitals, clinics and paramedic schools.</p></li><li><p><strong><a href="https://review.firstround.com/productboards-path-to-product-market-fit/">Productboard&#8217;s seven dimensions</a>:</strong> company size, product stage, digital-first or digital transformation, single or multiple products, size of the product organization, care for the customer, B2B or B2C. Which resolved to &#8220;an early stage, digital-first startup with strong customer-centric, product-led culture, with one product team, building a single (ideally) B2B product.&#8221;</p></li><li><p><strong><a href="https://www.hubspot.com/hubfs/Agency/GTM%20-%20Product%20Resources%20(Justin)/Misc%20Reference%20Guides%20-%20PDFs/HubSpots%20Ideal%20Customer%20Profile%202024%20(NAM_EMEA).pdf">HubSpot&#8217;s own 2024 NAM/EMEA ICP</a>,</strong> which is rare in publishing its own numbers: 150+ employees, $100M-$500M revenue, software, IT and financial services, $4.6K average monthly deal size, 25% conversion rate, 75-90 day deal length.</p></li><li><p><strong><a href="https://www.peersignal.org/p/3-proven-icp-definition-templates">Adam Schoenfeld&#8217;s paragraph format</a></strong>, for teams that won&#8217;t read a table: &#8220;We are best for B2B SaaS companies with 75-5,000 employees in the US and Canada. Our ideal customers are growing revenue with a sales-led motion, have 10+ AEs assigned to account-based territories, have sophisticated revenue operations...&#8221;</p></li><li><p><strong><a href="https://gtm-labs.co/ideal-customer-profile">GTM Labs&#8217; worked example</a></strong> is the one I&#8217;d hold up as the standard for specificity: 100-500 engineer companies on Kubernetes spending $5K+/month on Datadog, where a Senior SRE is the technical champion and the VP Engineering owns the budget, triggered by a Datadog renewal within 60 days.</p></li></ul><h3>The disqualifier section</h3><p>A negative ICP is a distinct, named section. <a href="https://www.linkedin.com/posts/j-16coelho_gtm-revops-pipelinemanagement-activity-7458126566678605824-m8dQ">Jo&#227;o Coelho</a> treats them as separate architecture: &#8220;Disqualification criteria are not the inverse of ICP. They&#8217;re a separate architectural decision.&#8221;</p><p><a href="https://coldicp.com/negative-icp-b2b-outbound/">Three exclusion types</a>: hard (never target, such as a size floor or a country you cannot legally support), soft (target only with a different motion, such as enterprise logos needing field sales rather than cold email), and conditional (target only if a trigger overrides the default, such as a smaller company that just raised).</p><p>Concrete dimensions people actually write down: pre-revenue companies with no paid motion, or <a href="https://www.contactlevel.com/resources/ideal-customer-profile-b2b">sub-200 employees when</a> the deal size is too small; <a href="https://pipeline.zoominfo.com/marketing/ideal-customer-profile">agencies reselling without</a> their own list, or project-based engagements under $25K; <a href="https://ziellab.com/post/ideal-customer-profile-b2b-guide">a champion with</a> no budget authority and no path to a decision-maker; missing core integrations; and <a href="https://prospectory.ai/resources/negative-persona-disqualification-framework/">a company eight</a> months into a three-year contract with a direct competitor.</p><p>Then make it mechanical. A <a href="https://prospectory.ai/resources/negative-persona-disqualification-framework/">multi-signal routing rule</a>: three or more negative signals auto-disqualifies, two routes to manual review, one proceeds but flags in the CRM. And the enforcement point that <a href="https://coldicp.com/negative-icp-b2b-outbound/">matters most</a>: &#8220;Do not rely on rep discretion. Use CRM views, enrichment rules, and sequence entry criteria. If a segment is truly a negative ICP, the system should block it before it reaches a sender account.&#8221;</p><p>The CRO at Consensus built the positive version of this out of win-loss data and called it a UCP, an un-ideal <a href="https://www.clozd.com/blog/how-consensus-improved-win-rates-using-clozd">customer profile</a>: &#8220;We now know exactly what a bad prospect looks like,&#8221; which they tied to a more streamlined sales process and lower churn.</p><h3>Who owns it, and where it lives</h3><p>Two artifacts, not one. The narrative version lives in a shared doc: <a href="https://fullfunnel.io/ideal-customer-profile/">Full Funnel publishes a Google Sheet</a>, <a href="https://www.hubspot.com/hubfs/hubspot-technology-partner-icp-and-jvp-template.pdf">HubSpot a PDF worksheet</a>. The enforced version lives in the CRM as <a href="https://ziellab.com/post/ideal-customer-profile-b2b-guide">an ICP fit</a> score (number, 0-100) and an ICP tier (dropdown: Tier 1, 2, 3, Not a fit) on the company object.</p><p>Ownership goes to <a href="https://ziellab.com/post/ideal-customer-profile-b2b-guide">RevOps where that function exists</a>, &#8220;or if you don&#8217;t have RevOps yet, whoever manages the CRM and the go-to-market cadence.&#8221; Earlier than that it belongs to the <a href="https://review.firstround.com/the-most-common-go-to-market-questions-from-founders/">founders</a> because &#8220;when you&#8217;re super early, everything should still be sales-led. You&#8217;re still figuring out your ICP and personas, and that requires talking to customers.&#8221; When conversion is inconsistent rather than absent, <a href="https://review.firstround.com/why-startup-marketers-should-be-diagnosticians-advice-from-stripe-and-openais-first-marketing-hire/">product marketing is the better owner</a>. <a href="https://www.hubspot.com/make-my-persona/ideal-customer-profile-template">HubSpot&#8217;s cadence</a>: &#8220;review it every quarter using fresh CRM data, closed-won deal patterns, and updated customer feedback.&#8221;</p><h2>How do you score and tier accounts?</h2><p>Four scoring models require progressively more data.</p><ul><li><p><strong>Weighted point-based</strong>, the <a href="https://clearbit.com/resources/books/data-driven-sales/inbound-lead-qualification">simplest thing that works</a>. 500+ employees +50, Director title +10, industry, country and technology 1-5 each, negative values for non-ICP attributes. Clearbit describes the <a href="https://clearbit.com/resources/books/lead-qualification/lead-scoring-stages">progression</a> from basic firmographic filtering to weighted points to predictive models, which is the order to walk it.</p></li><li><p><strong>Weighted rubric.</strong> A <a href="https://abmatic.ai/blog/how-to-set-up-account-scoring">two-layer model</a>: industry 20, employee count 20, revenue band 15, tech-stack adjacency 15, geography 10, funding and growth 10, hiring 10, each scored 100/60/30/0 by band. Combined as <a href="https://abmatic.ai/blog/account-scoring-implementation-guide">Account Score</a> =<code>(0.4 &#215; Fit) + (0.6 &#215; Intent)</code>, with intent recency multipliers of 1.0&#215; for 0-30 days, 0.5&#215; for 30-90, 0.1&#215; beyond. A <a href="https://reachiq.ai/resources/playbooks/icp-scoring-101/">published variant</a> weights firmographics 40%, technographics 25%, intent 20%, behavior 15%, with 70+ qualified, 50-69 worth working, under 50 disqualified. <a href="https://salesmotion.io/blog/icp-template-build-validate-activate">Another</a> is industry 25%, size 20%, tech stack 15%, growth signals 15%, org maturity 10%, geography 10%, negative filters 5%.</p></li><li><p><strong>Decision-tree look-alike.</strong> <a href="https://help.madkudu.com/docs/how-is-the-customer-fit-score-calculated">MadKudu&#8217;s model</a> uses firmographic, demographic and technographic data only for fit, with behavior in a separate <a href="https://help.madkudu.com/docs/lead-grade-scoring">Likelihood to Buy model</a> recomputed several times daily and combined as <code>Lead Grade = 2&#215; Fit + 1&#215; LTB</code>. Bands: Very Good 85-100, Good 70-84, Medium 50-69, Low 0-49. <a href="https://www.madkudu.com/blog/lead-scoring-model">Validation targets</a>: recall above 70%, precision as a 10&#215; conversion ratio between top and bottom scores, rejection rate under 5% for top scores.</p></li><li><p><strong>Customer-specific predictive.</strong> <a href="https://support.6sense.com/v1/docs/account-profile-fit-model">6sense</a> trains a model per customer on firmographics, technographics and custom fields, and the model itself identifies which characteristics matter. Bands Strong 81-100, Moderate 50-80, Weak 0-49, updated daily.</p></li></ul><p>Two rules apply across all four models. Hard disqualifiers stay <a href="https://hyperspect.ai/blog/icp-definition-framework">binary</a>: never let a high firmographic score buy its way past an exclusion. And if you have two or three segments with meaningfully different win criteria, <a href="https://ven.studio/blog/icp-definition-revops">build separate models</a>, because blending obscures the signal.</p><h3>Tiering</h3><p><a href="https://hginsights.com/blog/how-to-build-a-b2b-data-enrichment-strategy-that-scales-with-ai/">ICP fit</a> is the eligibility gate; intent, timing and signal strength determine tier placement. Composite formulas exist if you want one: <a href="https://prospeo.io/s/account-prioritization">(ICP Fit &#215; 0.30)</a> + (Intent &#215; 0.25) + (Engagement &#215; 0.25) + (Revenue Potential &#215; 0.20), or <a href="https://www.avair.ai/resources/blog/framework-tiering-target-accounts">fit 30%, revenue</a> potential 25%, intent 20%, engagement 15%, strategic value 10%.</p><p>What matters more is tying each tier to <a href="https://www.octavehq.com/post/gtm-engineers-guide-to-account-tiering">a motion and a volume</a> rather than to enthusiasm:</p><p><strong>Tier 1</strong> is a perfect fit across all dimensions, $100K+ ACV in the worked example, 10-25 accounts per rep, custom outbound with exec engagement and ABM ads, five to eight touches a week, fully personalized.</p><p><strong>Tier 2</strong> is a strong fit with one or two minor mismatches, $25K-$100K, 25-50 accounts per rep, programmatic ABM with industry-segmented messaging, two or three touches a week, semi-personalized.</p><p><strong>Tier 3</strong> is a partial fit that clears the minimum, under $25K, 100+ accounts per rep, inbound and paid social and self-serve, one automated touch, templated.</p><p>For calibration, <a href="https://blog.hubspot.com/sales/account-based-sales">HubSpot</a> runs Tier 1 at 20-50 accounts with &#8220;deep research and one-to-one customized outreach&#8221; and Tier 2 at roughly 200 with industry and persona personalization. <a href="https://winningbydesign.com/wp-content/uploads/2022/05/Winning-by-Design_Blueprint_How-to-Calculate-Your-Target-Account-List.pdf">ACV maps to load</a>: 20-50 accounts per rep in field sales at $50K-$500K ACV, 50-150 in a two-stage motion at $10K-$50K. <a href="https://www.growthunhinged.com/p/icp-marketing-done-right">Mutiny</a> shows what real separation looks like: Tier A converted lead-to-opportunity at 30%, Tier B at 8%, and Tiers C and D were &#8220;effectively rounding errors.&#8221; Oliver Jay started with 100 enterprise accounts at Asana and <a href="https://review.firstround.com/podcast/the-new-plg-playbook-arming-the-next-generation-of-product-led-companies-oliver-jay-asana-dropbox/">concluded</a> &#8220;that&#8217;s too many. It should have been just 50.&#8221;</p><p>Tiers should move. <a href="https://predictablerevenue.com/how-to-fish-in-the-same-pond-without-pissing-everyone-off/">Mosaic</a> narrowed 100,000 accounts to 8,000 managed by nine BDRs, with accounts crossing tiers annually as funding, size, geography and stack change. One team <a href="https://www.saastr.com/backstory-retiered-its-entire-customer-base-in-3-days-the-same-exercise-used-to-take-five-teams-a-quarter/">re-tiered</a> its entire customer base in three days on four signals (growth potential, AI maturity, engagement, account health), landing on 8 Tier A accounts and 21 Tier B.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!6wRJ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6641bed0-e881-4882-81ba-11b54ddc621b_1536x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!6wRJ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6641bed0-e881-4882-81ba-11b54ddc621b_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!6wRJ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6641bed0-e881-4882-81ba-11b54ddc621b_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!6wRJ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6641bed0-e881-4882-81ba-11b54ddc621b_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!6wRJ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6641bed0-e881-4882-81ba-11b54ddc621b_1536x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!6wRJ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6641bed0-e881-4882-81ba-11b54ddc621b_1536x1024.png" width="1456" height="971" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6641bed0-e881-4882-81ba-11b54ddc621b_1536x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:971,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1255381,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://journal.daniellopes.dev/i/212372039?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6641bed0-e881-4882-81ba-11b54ddc621b_1536x1024.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!6wRJ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6641bed0-e881-4882-81ba-11b54ddc621b_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!6wRJ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6641bed0-e881-4882-81ba-11b54ddc621b_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!6wRJ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6641bed0-e881-4882-81ba-11b54ddc621b_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!6wRJ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6641bed0-e881-4882-81ba-11b54ddc621b_1536x1024.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><h3>Trigger events</h3><p>Six categories, across 6sense, Bombora, ZoomInfo, Demandbase, Common Room and UserGems: <a href="https://docs.zoominfo.com/docs/signals-insights">capital and funding</a>; <a href="https://www.demandbase.com/faq/intent-signals/">leadership changes</a>, where UserGems reports <a href="https://help.usergems.com/article/signals-overview">past champions</a> &#8220;convert about 3x higher than normal leads&#8221;; hiring and job postings, which <a href="https://www.commonroom.io/docs/signals/common-room-native-signals/job-listings/">reveal strategic priorities</a>; technology adoption or replacement, where HG Insights&#8217; technographic flags produce <a href="https://hginsights.com/blog/how-to-create-an-ideal-customer-profile-icp/">up to a 5x conversion rate to opportunity</a>; <a href="https://help.usergems.com/article/signals-overview">expansion news</a>; and <a href="https://docs.zoominfo.com/docs/signals-insights">layoffs or contraction</a>, which can indicate consolidation needs.</p><p>First-party intent has its own ladder, from <a href="https://clearbit.com/blog/how-to-use-webpage-intent">Clearbit</a>: high intent is pricing, SKU, trial and demo pages; medium is customer stories, solutions, partners and integrations; low is the homepage, about page and blog.</p><h3>Measuring the ICP itself</h3><p>Not just the accounts. <a href="https://diggrowth.com/blogs/analytics/kpis-metrics-to-measure-icp-accuracy-and-performance/">ICP pipeline contribution</a> as a share of opportunities by count and by dollars, <a href="https://ven.studio/blog/revops-kpis-that-matter">win rate and deal velocity by tier</a>, and <a href="https://www.revopscoop.com/webinar-series/accelerating-revenue-by-the-numbers">renewal rate by tier</a>.</p><p>Bessemer <a href="https://www.bvp.com/atlas/scaling-gtm-from-25-to-50-million-arr">stages the reporting</a>: &#8220;At $1M ARR it is common to look at total pipeline, but at $25-50M this pipeline should be segmented by ICP targets&#8221; and split new-logo from expansion. Coverage benchmarks to hold it against: <a href="https://www.bvp.com/atlas/scaling-to-100-million-ramping-your-cloud-gtm-engine">3-5&#215; the ARR goal</a> unweighted, 2&#215;+ weighted in-period, and $8-10 of pipeline per $1 of marketing spend.</p><h2>How should an ICP change by stage, and how often should you revisit it?</h2><p><strong>Pre-PMF: uncomfortably narrow.</strong> Paul Graham&#8217;s version is to <a href="https://paulgraham.com/13sentences.html">satisfy</a> &#8220;all the needs of a subset of potential users&#8221; rather than a subset of the needs of all of them. <a href="https://www.ycombinator.com/blog/ycs-essential-startup-advice">YC</a>: &#8220;recruiting 10 customers who have a burning problem is much better than 1000 customers who have a passing annoyance.&#8221; Bessemer says to <a href="https://www.bvp.com/atlas/the-founders-playbook-for-scaling-to-1-million-arr">make it narrow</a> &#8220;uncomfortably narrow, so narrow it almost feels too small,&#8221; to focus on one ICP at a time even when the product has broad applications, and to avoid targeting enterprises first. First Round&#8217;s Emery Rosansky <a href="https://review.firstround.com/the-most-common-go-to-market-questions-from-founders/">sets the epistemics</a>: &#8220;in the early days, you&#8217;re flying nearly blind with a small amount of data, so this initial ICP is not much more than an educated hypothesis.&#8221;</p><p>The obstacle at this stage is usually not ignorance. Clay&#8217;s Kareem Amin <a href="https://review.firstround.com/clays-path-to-product-market-fit/">names it</a>: &#8220;Often it&#8217;s not that you don&#8217;t know who the customer is, it&#8217;s that you&#8217;re not picking, you haven&#8217;t committed to one hypothesis over the other.&#8221; When Clay did narrow, it enforced the choice by cutting irrelevant features, removing non-tailored marketing language, updating internal docs and re-educating the team. Cadence here is event-driven, not calendar-driven.</p><p>Two findings from Rachitsky&#8217;s founder interviews pull in opposite directions. Most founders got their first ICP wrong, so the exercise is iteration rather than insight: Persona&#8217;s Rick Song ran it <a href="https://www.lennysnewsletter.com/p/how-to-identify-your-ideal-customer">&#8220;17 times in the early days,&#8221;</a> and Databricks had none at all, working with &#8220;a hospital that was using this stuff... folks that were using us to determine earthquake magnitudes using Twitter.&#8221;</p><p>Skipping the exercise can slow product-market fit. Mathilde Collin at <a href="https://www.lennysnewsletter.com/p/how-to-identify-your-ideal-customer">Front</a>: &#8220;We did not think about ICP. I wish we did earlier on. It&#8217;s one of my biggest mistakes.&#8221; Barry McCardel at Hex was forced into it by launch: &#8220;once we did our public launch, we started getting a flood of different people coming in. Filtering through the leads spurred me into putting a much tighter definition around qualification for deals.&#8221;</p><p><strong>Series A/B: evidence-driven narrowing.</strong> a16z <a href="https://a16z.com/how-much-should-i-invest-in-revops/">frames the stage</a> &#8220;rapidly experimenting to refine your ideal customer profile and build repeatable sales motions.&#8221; Bessemer&#8217;s ARR ladder is the most specific guidance available: at <a href="https://www.bvp.com/atlas/scaling-from-1-to-10-million-arr">$1-10M ARR</a>, &#8220;aim to fulfill the product vision for your initial ideal customer profile,&#8221; sequencing product-market fit, then strong net retention in the ICP base, then broadening; at <a href="https://www.bvp.com/atlas/scaling-to-100-million-ramping-your-cloud-gtm-engine">$10-25M</a>, &#8220;it becomes important to start segmenting leads to the salespeople and sales teams who are best equipped to handle them&#8221;; at <a href="https://www.bvp.com/atlas/scaling-gtm-from-25-to-50-million-arr">$25-50M</a>, &#8220;crystallizing your ideal customer profile&#8221; becomes one of the most important tasks, and you finally have enough deals to find the pattern.</p><p><a href="https://openviewpartners.com/blog/market-segmentation-how-why-when/">OpenView&#8217;s analytical method</a> for this stage: &#8220;Pull all of your opportunities from the past year and clean the data. Look for the expected LTV per opportunity versus the CAC across different characteristics, such as industry, company size, buyer persona and use case.&#8221; With the caution that firmographics alone &#8220;does not drive any particularly important insights.&#8221;</p><p>Jason Lemkin puts numbers on when to split the team: begin segmenting <a href="https://www.saastr.com/how-should-your-approach-to-segmenting-customers-change-as-your-sales-team-scales-up/">&#8220;as early as 3 reps,&#8221;</a> formalize three or four categories &#8220;after maybe $8m-$10m ARR.&#8221; Stripe <a href="https://openviewpartners.com/blog/scaling-sales-stripe/">added one segmentation dimension per year</a> starting with size, and Jeanne DeWitt Grosser describes the failure mode: &#8220;You know you have a segmentation problem when the same account executive is talking to a million-dollar company in the morning and a billion-dollar company in the afternoon. Those sales processes have nothing to do with one another.&#8221; Cadence: a quarterly playbook review, and Mandy Cole&#8217;s instruction is to check it <a href="https://www.saastr.com/5-steps-to-build-your-first-gtm-playbook-with-stage-2-capital/">against reality</a>: &#8220;Go through and see if it&#8217;s what you&#8217;re doing in the field, and if it&#8217;s not, update it to see the impact on pipeline.&#8221;</p><p><strong>Enterprise: a new ICP, not an extension.</strong> Joe Morrissey at a16z warns against treating <a href="https://a16z.com/getting-ready-to-move-upmarket/">interest as fit</a>: &#8220;the single biggest mistake I&#8217;ve seen companies make when moving upmarket is mistaking initial enterprise interest for product-market fit. Just because you have product-market fit for startups, SMBs, or mid-market customers does not mean you&#8217;ll automatically find product-market fit in the enterprise space.&#8221; Segment&#8217;s enterprise ICP was &#8220;larger enterprises that were B2C, multi-product, multi-brand, multi-subsidiary, and most importantly, data-literate,&#8221; narrowed further to those with &#8220;forward-thinking data champion buyers who were either decision-makers or could partner with a CMO to shape the decision criteria,&#8221; and it required outbound pipeline generation with 9-12 month cycles.</p><p>Budget for the new segment differently. <a href="https://www.saastr.com/your-core-cac-vs-your-expansion-cac-one-trophy-but-two-goals/">Lemkin</a>: &#8220;If you force your CAC in a new segment to hit the same ROI as your overall, blended CAC goals, you&#8217;ll never leave your core safe ICP,&#8221; so 80% of new customers should hit a sustainable CAC while the 20% in new segments &#8220;just try to barely break even,&#8221; with 24 months to converge.</p><p>At this size the data team becomes the reality check. <a href="https://www.bvp.com/atlas/how-to-get-more-out-of-your-startups-data-strategy">Bessemer</a>: &#8220;The data team will come in and identify the users who have high product engagement, retention, and reach, and in many cases, the attributes of this cohort of users will differ, at least somewhat, from an original conception of the ideal customer.&#8221; And a16z&#8217;s point about who <a href="https://a16z.com/podcast/do-you-know-your-icp/">holds the pieces</a>: &#8220;You can&#8217;t define your ICP in a silo. RevOps has data. Product sees patterns. Sales hears objections. Marketing picks up signal. Success sees who churns and who expands.&#8221;</p><p><strong>Review versus revision.</strong> The cadence argument resolves once you separate the two words. Review is checking evidence: monthly or quarterly against live closed-won data, which is what Anis Bennaceur at <a href="https://www.saastr.com/how-attention-com-turns-sales-calls-into-pipeline-the-best-gtm-data-you-own-and-why-most-b2b-teams-throw-it-away/">Attention.com</a> means by &#8220;the teams compounding fastest are refreshing it off live closed-won data on a monthly or quarterly loop.&#8221; Revision is changing the operating definition, and it should be rare and trigger-based: <a href="https://a16z.com/framework-define-refine-icp/">a new product</a> capability that changes who you can serve, <a href="https://openviewpartners.com/blog/market-segmentation-how-why-when/">retention, win rates, service</a> costs or willingness to pay differing by segment, <a href="https://a16z.com/aligning-product-and-gtm-teams-with-better-segmentation/">a move upmarket</a>, or <a href="https://www.bvp.com/atlas/how-to-get-more-out-of-your-startups-data-strategy">behavioral data diverging</a> from the original conception.</p><p>The apparent disagreement in the sources resolves the same way. <a href="https://gtm-labs.co/ideal-customer-profile">Daria Dovzhikova</a> supports full rebuilds after major launches or funding rounds; <a href="https://erikrmiller.com/icp/">Erik Miller</a> warns &#8220;Don&#8217;t change the ICP every quarter; that creates whiplash for sales and marketing.&#8221; Both are right, about different words.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!u4A9!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F07b41362-41e2-4e84-8584-6045280793ec_1536x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!u4A9!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F07b41362-41e2-4e84-8584-6045280793ec_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!u4A9!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F07b41362-41e2-4e84-8584-6045280793ec_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!u4A9!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F07b41362-41e2-4e84-8584-6045280793ec_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!u4A9!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F07b41362-41e2-4e84-8584-6045280793ec_1536x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!u4A9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F07b41362-41e2-4e84-8584-6045280793ec_1536x1024.png" width="1456" height="971" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/07b41362-41e2-4e84-8584-6045280793ec_1536x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:971,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1458499,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://journal.daniellopes.dev/i/212372039?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F07b41362-41e2-4e84-8584-6045280793ec_1536x1024.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!u4A9!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F07b41362-41e2-4e84-8584-6045280793ec_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!u4A9!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F07b41362-41e2-4e84-8584-6045280793ec_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!u4A9!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F07b41362-41e2-4e84-8584-6045280793ec_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!u4A9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F07b41362-41e2-4e84-8584-6045280793ec_1536x1024.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><h2>How the ICP shows up downstream: positioning, outbound, roadmap, board</h2><p>A definition nothing enforces isn&#8217;t a definition.</p><p><strong>Positioning.</strong> April Dunford <a href="https://www.aprildunford.com/post/an-introduction-to-positioning">defines positioning</a> &#8220;how your product is a leader at delivering something that a well-defined set of customers cares a lot about,&#8221; and the order of her five components is the argument for where the ICP sits: <a href="https://www.aprildunford.com/post/positioning-and-competition">competitive alternatives</a> (&#8221;what would customers do if our solution didn&#8217;t exist?&#8221;), differentiated capabilities, value, <em>then</em> target customer segmentation, then <a href="https://www.aprildunford.com/post/a-quickstart-guide-to-positioning">market category</a>. The ICP is derived from unique value rather than assumed before it, because &#8220;your best-fit target customers are customers that really care a lot about your unique value.&#8221; Starting from market category is <a href="https://aprildunford.substack.com/p/understanding-the-job-of-a-market">&#8220;the tail wagging the dog.&#8221;</a></p><p>The payoff, in her <a href="https://www.aprildunford.com/post/a-product-positioning-exercise">words</a>: &#8220;Customers that are well suited for your offering will easily understand your value, will purchase faster, and are much less likely to ask for discounts.&#8221; The canonical case is repositioning a general enterprise CRM, which invited comparison with Siebel, as a <a href="https://www.aprildunford.com/post/a-quickstart-guide-to-positioning">CRM for investment banks</a> where modeling interpersonal relationships was mission-critical: &#8220;from under $2M to close to $80M&#8221; in 18 months.</p><p><strong>Demand generation.</strong> Chris Walker&#8217;s paid-social <a href="https://www.linkedin.com/posts/chriswalker171_marketing-b2b-demandgen-activity-6892102282540929024-8Yd_">targeting formula</a> is just &#8220;(1) Job Title + (2) Company firmographics (named accounts, company size, industry),&#8221; with the classic errors being no job-title targeting, no firmographic layer, and LinkedIn audience expansion that makes you &#8220;pay high CPMs to people you don&#8217;t want to reach.&#8221; Refine Labs allocates <a href="https://www.refinelabs.com/article/partnerships-0">60-70% of paid</a> media to demand creation and about 30% to capture.</p><p>Budget for the measurement gap while you&#8217;re at it. Across 620 declared-intent conversions and $21.5M in closed-won ARR, Refine Labs found <a href="https://www.refinelabs.com/news/hybrid-attribution-framework">a 90% gap</a> between software attribution and first-party self-reported data: podcast was credited with 53% of revenue self-reported and 0% by software.</p><p>Three worked outcomes. <a href="https://www.refinelabs.com/success-stories/clari">Clari</a> moved to target account lists, persona alignment and zero-click content instead of lead-gen forms: ad spend down 38%, cost per SQO down 36%, acquisition cost down 67%, win rates up 64%. <a href="https://www.refinelabs.com/success-stories/loxo">Loxo</a> built priority account lists with buyer-count exclusions and ICP-focused content: acquisition cost down 23%, ARR up 45% quarter over quarter. <a href="https://www.refinelabs.com/success-stories/zappi">Zappi</a> analyzed region, industry and persona out of the CRM and targeted by job function: 3&#215; average deal size and 7&#215; qualified pipeline against spend.</p><p><strong>Outbound.</strong> Clay&#8217;s method is the ICP definition and the list build in <a href="https://www.clay.com/guides/how-to-build-a-targeted-prospect-list">one motion</a>: &#8220;Pull the deals that closed fast, stayed, and expanded, and ask what they had in common the quarter before they bought. The patterns that repeat are your ICP. Write the definition down as a list of filters you can source against later, split into firmographic (size, industry, geography), technographic (the tools they run), and signal-based (funding, hiring, expansion).&#8221;</p><p>Apply disqualifiers <em>before</em> <a href="https://prospectingmanual.com/icp-to-sequence-workflow/">list export</a> since &#8220;disqualifiers applied after export waste enrichment credits and create compliance risk.&#8221; The <a href="https://learn.outboundsystem.com/playbooks/sales-nav-targeting">workflow</a> most teams end up with: build criteria in Sales Navigator, export, run through Apollo or ZoomInfo for contact data, layer Crunchbase for funding, overlay BuiltWith for technographics, process through Clay for dedup and scoring. With one caveat worth pinning up: &#8220;Company headcount is the least reliable filter in Sales Navigator. Many companies mischaracterize their size or list no headcount at all.&#8221;</p><p><strong>Content.</strong> The operating chain is ICP and account fit, then priority personas and buying situations, then topic pillars, then stage-appropriate formats, then channels. <a href="https://www.reforge.com/blog/buyer-persona">Every campaign, product</a> and content strategy should align to at least one persona, built on &#8220;motivations, goals, pain points, and language, not only demographics.&#8221; Exit Five&#8217;s practical step is the one <a href="https://exitfive.com/newsletter/b2b-marketing-first-principles-you-need-to-nail-exit-five-newsletter-132/">teams skip</a>: &#8220;Create a One-Pager: Summarize your ICP in one clear document that your entire team can use.&#8221; For volume calibration, <a href="https://www.reforge.com/blog/brief-does-content-marketing-actually-work-the-data-says-yes">47% of buyers</a> view three to five pieces of content before talking to a rep.</p><p><strong>Roadmap.</strong> The <a href="https://discover.gtmplaybook.co/ideal-customer-profile-template-b2b-saas">ICP</a> &#8220;should be a formal input into quarterly roadmap reviews, not just a Marketing document.&#8221; A <a href="https://www.pelin.ai/blog/prioritizing-feedback-from-different-customer-segments">segment-weighted score</a> makes the tradeoff explicit: revenue &#215; strategic fit &#215; growth signal &#215; usage depth. Worked: a $30K mid-market account that is a core ICP match, expanding, and a power user scores 108; a $100K enterprise outlier that is contracting and lightly used scores 5, making &#8220;the mid-market account&#8217;s feedback 21x more valuable for prioritization purposes.&#8221; The <a href="https://www.reforge.com/blog/product-roadmaps">counterweight</a> keeps it honest: over-indexing on power users &#8220;harms the product experience for the rest of the user base, and steals product effort away from features that could go towards acquiring new users.&#8221;</p><p><strong>Board reporting.</strong> a16z flags <a href="https://a16z.com/11-key-gtm-metrics-for-b2b-startups/">Net New Weighted Pipeline</a> as the leading indicator of market pull. Pair each metric with the decision it drove, since <a href="https://a16z.com/what-now-board-meeting-or-bullsht/">70% of a board meeting</a> should focus on the future and the issues at hand. First Round&#8217;s Vanta example is the model: a 6% win rate on one <a href="https://review.firstround.com/annual-planning-sucks-a-cpo-cro-cfo-and-coo-share-advice-on-how-to-make-it-better/">product-buyer combination</a> where &#8220;generally, a win rate below 30% means salespeople are wasting time and you need an unsustainable amount of pipeline. In this case, the solution wasn&#8217;t to fix sales, but to immediately stop selling this product to this buyer.&#8221; And SaaStr&#8217;s <a href="https://www.saastr.com/nothing-else-segment-churn/">observed NRR gradient by deal size</a> makes the segment story concrete: single-seat deals under $99/month at roughly 3% monthly churn, $99-$999 at about 100% NRR, $10K-$100K+ at about 120%.</p><h2>Why do ICPs fail?</h2><p><a href="https://19965450.fs1.hubspotusercontent-na2.net/hubfs/19965450/2026%20Benchmarks%20Report%20Assets/Fullcast_Pavillion-2026-GTM-Benchmark%20Report.pdf">Fullcast and Pavilion&#8217;s 2026 GTM benchmark</a> found ICP misalignment cuts win rates by up to 75%, and that 63% of 118 CROs had little or no confidence in their own ICP. Nobody in that survey is missing a document. They just don&#8217;t believe theirs.</p><p>Nine failure modes, in the order I&#8217;d expect to hit them rather than the order they&#8217;re usually listed.</p><ol><li><p><strong>Written but not operationalized.</strong> <a href="https://b2brevopsinsights.com/how-to-operationalize-your-icp-across-the-funnel/">The pattern</a>: &#8220;ICP alignment is not a strategy doc... You defined your ICP in a slide deck three quarters ago. But you haven&#8217;t updated routing rules since.&#8221; Owner.com&#8217;s CRO Kyle <a href="https://www.saastr.com/how-to-build-go-to-market-efficiency-in-smb-sales-with-owner-com-cro-kyle-norton/">Norton found</a> &#8220;either bad or no targeting on prospects,&#8221; poor-fit closes and mis-set expectations, with churn a &#8220;massive drag on efficiency&#8221; in his first 90 days; his fix was to pause the Growth plan, say no to a lot of customers, and build a lead quality system. <em>Remedy:</em> audit the top 50 closed-won deals against current scoring and routing rules. Figma&#8217;s version was to <a href="https://review.firstround.com/podcast/inside-figmas-early-days-how-to-build-a-world-class-sales-org-kyle-parrish-vp-of-sales/">segment sales at</a> the 1,000-employee line and pipe product usage into Salesforce via reverse ETL.</p></li><li><p><strong>Static.</strong> One RevOps lead <a href="https://www.linkedin.com/posts/kurt-warner-8699b63_icp-drift-is-killing-your-pipeline-and-no-activity-7477723074906308608-QEeZ">describes a client</a> that &#8220;re-wrote their ICP properly last year, negative criteria and all, then left the old scoring weights and routing rules untouched for two quarters. The doc said one thing, the system kept qualifying the drifted accounts, and nobody reconciled the two until win rate forced it,&#8221; calling drift a &#8220;silent revenue killer manifesting as declining win rates, lengthening sales cycles, and churn concentration.&#8221; Lemkin&#8217;s line: <a href="https://www.saastr.com/how-attention-com-turns-sales-calls-into-pipeline-the-best-gtm-data-you-own-and-why-most-b2b-teams-throw-it-away/">&#8220;an annual ICP exercise is a 2021 habit.&#8221;</a> <em>Remedy:</em> treat it as a <a href="https://www.ownoutbound.com/blog-posts/your-icp-isnt-a-spreadsheet-its-a-living-hypothesis">living hypothesis</a> with a monthly closed-won review. One founder who did that cut outbound from 2,000 to 400 emails a month while win rate rose from ~3% to 11%.</p></li><li><p><strong>Aspirational.</strong> The written ICP describes the customer the company wants; closed-won describes the one it has. <a href="https://ziellab.com/post/ideal-customer-profile-icp-data-driven-b2b-guide">The cost</a>: &#8220;The gap between those two is where marketing spend goes to die,&#8221; with an SDR team hitting an 11% win rate and a 178-day cycle against the written ICP. Sometimes the gap is a level, not a segment: First Round <a href="https://review.firstround.com/the-most-common-go-to-market-questions-from-founders/">documents a company</a> that &#8220;thought they were selling to CISOs at early- and growth-stage orgs, but realized through user research discussions that the people that acutely felt the pain were 2-3 levels below a CISO in an Enterprise org.&#8221; <em>Remedy:</em> start from 18-24 months of closed-won, and note Rachitsky&#8217;s finding that <a href="https://www.lennysnewsletter.com/p/how-to-identify-your-ideal-customer">data from outbound</a> sales beats leads from investors and friends as a signal.</p></li><li><p><strong>Too broad.</strong> Cascade&#8217;s Jake <a href="https://www.lennysnewsletter.com/p/lessons-learned-from-a-startup-that">Fuentes defined</a> &#8220;nontechnical business analysts using Excel to crunch big data sets,&#8221; later calling it &#8220;much too broad&#8221; and describing the result as ICP fray: a scooter company managing location data, an HR team and a retailer under one profile. &#8220;To know what problem you&#8217;re solving, you need to know who you&#8217;re solving it for.&#8221; <em>Remedy:</em> replace generic firmographics with operational signals, and start from about three distinctive attributes.</p></li><li><p><strong>Demographics instead of behavior and situation.</strong> A profile of static firmographics with nothing distinguishing accounts likely to buy <em>now</em>. <em>Remedy:</em> convert filters into real-time signals, and mine what you already own. Lemkin: <a href="https://www.saastr.com/how-attention-com-turns-sales-calls-into-pipeline-the-best-gtm-data-you-own-and-why-most-b2b-teams-throw-it-away/">prospect call transcripts</a> are &#8220;the highest-signal first-party data your company will ever own.&#8221;</p></li><li><p><strong>No negative ICP.</strong> <a href="https://www.clozd.com/blog/5-reasons-deals-are-lost-and-how-to-turn-them-into-wins">No-decision deals</a> &#8220;can account for up to 40% of a pipeline,&#8221; which is exactly what disqualifiers are for. <em>Remedy:</em> Mandy Cole&#8217;s <a href="https://www.saastr.com/5-steps-to-build-your-first-gtm-playbook-with-stage-2-capital/">Green/Yellow/Red</a>: green is proactive pursuit, yellow is inbound and referral only, red is no-go.</p></li><li><p><strong>No discipline at close.</strong> Quota pressure closes poor-fit deals. Katrina Wong separates an ICP from inbound demand: an ICP is <a href="https://www.saastr.com/saastr-podcast-457-and-video-building-your-ideal-customer-profile/">a choice</a> about &#8220;who you want to sell to versus who just wants to buy from you.&#8221; Clay&#8217;s co-founder Varun Anand gives the honest version of what <a href="https://review.firstround.com/the-gtm-inflection-points-that-powered-clay-to-a-1b-valuation/">discipline costs</a>: &#8220;We had few true customers because almost none of the existing ones fit our new ICP,&#8221; and after narrowing to outbound sales, &#8220;nearly all of our original customers churned.&#8221;</p></li><li><p><strong>Confusing ICP with persona.</strong> <em>Remedy:</em> keep <a href="https://ziellab.com/post/ideal-customer-profile-icp-data-driven-b2b-guide">the split</a> clean: &#8220;ICP answers &#8216;what kind of company should we go after.&#8217; Persona answers &#8216;who inside that company makes the call.&#8217;&#8221; Qualify the account first, then map the committee.</p></li><li><p><strong>Trusting CRM loss reasons.</strong> 15% buyer-seller alignment, 70% competitor mismatch, 98% inconsistent tracking, all cited above. <em>Remedy:</em> <a href="https://www.clozd.com/blog/how-to-build-a-worldclass-winloss-program-from-scratch">20 interviews within a segment</a> before concluding anything.</p></li></ol><p>The <a href="https://b2brevopsinsights.com/how-to-operationalize-your-icp-across-the-funnel/">single best test</a> of whether yours is real: an SDR can identify or disqualify an account quickly, marketing can target it, RevOps can score and route it, and sales can explain why it should be pursued <em>now</em>. If any of the four can&#8217;t, it&#8217;s a point of view rather than an ICP.</p><h2>Where the practice is heading</h2><p>The ICP-as-PDF is explicitly retired in current practice. <a href="https://blog.icustomer.ai/rethinking-icp-in-2025-the-icustomer-methodology-for-effective-abm-and-compounding-growth/">iCustomer, July 2025</a>: &#8220;The traditional definition of an Ideal Customer Profile as a static document describing your perfect customer is obsolete. In 2025, an ICP isn&#8217;t a document, it&#8217;s a dynamic, data-driven automated system that evolves in real-time based on live signals and market intelligence.&#8221;</p><p>Tooling now derives the profile directly. <a href="https://www.zoominfo.com/features/ideal-customer">ZoomInfo&#8217;s AI-Generated ICP</a> takes a CRM report of won and lost deals and learns which attributes indicate best targets, refreshing as conditions change. <a href="https://hginsights.com/product/market-analyzer-copilot/">HG Insights&#8217; Market Analyzer Copilot</a> builds ICPs from win/loss, firmographic and technographic data correlated with highest-CLV customers.</p><p>The capability gap is the more interesting number. <a href="https://enlyft.com/resources/will-2024-be-the-year-of-the-customer-insights-overhaul">Enlyft</a> found 81% of respondents likely to update their ICP in 2024, yet nearly 70% lacked a strong grasp of account scoring and 43% had invested in scoring without understanding its efficacy. The differentiator is not access to a model. It&#8217;s knowing what a good one looks like.</p><h2>Further reading</h2><ul><li><p>Lenny Rachitsky, <a href="https://www.lennysnewsletter.com/p/how-to-identify-your-ideal-customer">How to identify your ideal customer profile</a>. The operator counterpart to this page, and the best collection of initial ICPs anywhere: a nine-item attribute picker, a dozen founder accounts, and the three-attribute floor. It paywalls at the template and the comparison chart.</p></li><li><p>a16z, <a href="https://a16z.com/framework-define-refine-icp/">a framework to define and refine your ICP</a>, for the nine-field template and the revision triggers.</p></li><li><p>First Round Review, <a href="https://review.firstround.com/the-most-common-go-to-market-questions-from-founders/">the most common</a> go-to-market questions from founders, which is where the hiring-signal example and the &#8220;educated hypothesis&#8221; framing come from.</p></li><li><p>April Dunford, <a href="https://www.aprildunford.com/post/a-quickstart-guide-to-positioning">a quickstart guide to positioning</a>, for why the ICP comes after differentiated value rather than before it.</p></li><li><p><a href="https://fullfunnel.io/ideal-customer-profile/">Full Funnel&#8217;s ICP for ABM</a>, which publishes an actual Google Sheet.</p></li><li><p><a href="https://allstonlabs.com/library/icp/closed-won-deconstruction">Allston Labs on closed-won deconstruction</a>, the most rigorous small-sample method I found.</p></li><li><p><a href="https://www.clozd.com/blog/how-to-build-a-worldclass-winloss-program-from-scratch">Clozd on building a win-loss program</a>, for the interview thresholds and why CRM loss reasons mislead.</p></li><li><p>Clay&#8217;s account of what narrowing costs, which is the least comfortable line in the whole set: after <a href="https://review.firstround.com/the-gtm-inflection-points-that-powered-clay-to-a-1b-valuation/">they narrowed</a>, &#8220;nearly all of our original customers churned.&#8221;</p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!WVyC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3a8ebff-9856-40e4-988a-1e71609fd214_1448x1086.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!WVyC!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3a8ebff-9856-40e4-988a-1e71609fd214_1448x1086.png 424w, https://substackcdn.com/image/fetch/$s_!WVyC!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3a8ebff-9856-40e4-988a-1e71609fd214_1448x1086.png 848w, https://substackcdn.com/image/fetch/$s_!WVyC!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3a8ebff-9856-40e4-988a-1e71609fd214_1448x1086.png 1272w, https://substackcdn.com/image/fetch/$s_!WVyC!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3a8ebff-9856-40e4-988a-1e71609fd214_1448x1086.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!WVyC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3a8ebff-9856-40e4-988a-1e71609fd214_1448x1086.png" width="1448" height="1086" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e3a8ebff-9856-40e4-988a-1e71609fd214_1448x1086.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1086,&quot;width&quot;:1448,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1291817,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://journal.daniellopes.dev/i/212372039?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3a8ebff-9856-40e4-988a-1e71609fd214_1448x1086.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!WVyC!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3a8ebff-9856-40e4-988a-1e71609fd214_1448x1086.png 424w, https://substackcdn.com/image/fetch/$s_!WVyC!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3a8ebff-9856-40e4-988a-1e71609fd214_1448x1086.png 848w, https://substackcdn.com/image/fetch/$s_!WVyC!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3a8ebff-9856-40e4-988a-1e71609fd214_1448x1086.png 1272w, https://substackcdn.com/image/fetch/$s_!WVyC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3a8ebff-9856-40e4-988a-1e71609fd214_1448x1086.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>FAQ</h2><p><strong>What is an ideal customer profile?</strong> An account-level definition of which companies you are best at winning, serving, retaining and expanding, expressed as scored criteria and explicit disqualifiers rather than prose. It answers four questions: who will buy, who will buy smoothly, who can be implemented and serviced, and who will renew and expand.</p><p><strong>How is an ICP different from a buyer persona?</strong> The ICP is the company, the persona is the person inside it. Qualify the account first, then map the buying committee. Treating them as synonyms produces a profile that can&#8217;t be used for routing or list building.</p><p><strong>How is an ICP different from TAM?</strong> TAM is a dollar-value estimate of the whole opportunity. An ICP is a qualitative definition of which account types fit best. Every ICP account sits inside your TAM; most TAM accounts are not in your ICP.</p><p><strong>How many customers do you need before you can define one?</strong> 5-7 closed-won deals support a provisional hypothesis, 30 is a stronger first pass, and 50 combined won and lost supports general pattern analysis. Below that, use the top 3 by revenue and top 3 by retention as a quarterly-revised hypothesis, with closed-lost as the control group.</p><p><strong>How many attributes should an ICP have?</strong> Four to seven, and at least three. Past 8-10 dimensions you are over-specified and fitting noise, and the profile stops being usable by an SDR in real time.</p><p><strong>How often should you update an ICP?</strong> Review monthly or quarterly against live closed-won data. Revise the operating definition only on a trigger: a new capability that changes who you can serve, retention or unit economics splitting by segment, a move upmarket, or behavioral data diverging from the original conception. Rewriting it every quarter creates whiplash in sales and marketing.</p><p><strong>Who owns the ICP?</strong> One named owner with a change log, usually RevOps or whoever manages the CRM and the go-to-market cadence, with input from product, sales, marketing and customer success. At the earliest stage it belongs to the founders, because it is still being discovered in customer conversations.</p><p><strong>Do you need a negative ICP?</strong> Yes, as its own section rather than the inverse of the positive criteria. Split hard exclusions you never target from soft ones you serve on inbound and referral only, and conditional ones a trigger can override. No-decision deals can reach 40% of a pipeline, and disqualifiers are what protect it.</p><p><strong>Where should the ICP document live?</strong> Two places. A shared doc for the narrative version, and the CRM for the enforced version, as a fit score and a tier on the company object. If it only exists in the doc, it isn&#8217;t operating.</p><p><strong>What is the difference between fit and intent?</strong> Fit is whether a company should buy from you, from stable attributes. Intent is whether it is looking right now, from recent signals. Score them separately and combine at routing: fit sets eligibility, intent and timing set the tier.</p><p><strong>How do you know the ICP is working?</strong> Track ICP share of pipeline by count and dollars, win rate by tier, deal velocity by tier, and renewal rate by tier. If Tier 1 doesn&#8217;t convert materially better than Tier 3, the tiers are decorative.</p>]]></content:encoded></item><item><title><![CDATA[Paul Graham's essays, as audio]]></title><description><![CDATA[Collection of his  classic essays &#8212; narrated, chaptered, and grouped by theme.]]></description><link>https://journal.daniellopes.dev/p/paul-grahams-essays-as-audio</link><guid isPermaLink="false">https://journal.daniellopes.dev/p/paul-grahams-essays-as-audio</guid><dc:creator><![CDATA[Daniel Lopes]]></dc:creator><pubDate>Mon, 24 Aug 2026 17:09:53 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/864e78a3-b5e1-4f6d-8c25-701e07ebe68a_1672x941.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Znjb!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a64829f-17d6-4a9e-babc-17361786a4a7_1672x941.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Znjb!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a64829f-17d6-4a9e-babc-17361786a4a7_1672x941.png 424w, https://substackcdn.com/image/fetch/$s_!Znjb!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a64829f-17d6-4a9e-babc-17361786a4a7_1672x941.png 848w, https://substackcdn.com/image/fetch/$s_!Znjb!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a64829f-17d6-4a9e-babc-17361786a4a7_1672x941.png 1272w, https://substackcdn.com/image/fetch/$s_!Znjb!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a64829f-17d6-4a9e-babc-17361786a4a7_1672x941.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Znjb!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a64829f-17d6-4a9e-babc-17361786a4a7_1672x941.png" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8a64829f-17d6-4a9e-babc-17361786a4a7_1672x941.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1048568,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://journal.daniellopes.dev/i/212491348?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a64829f-17d6-4a9e-babc-17361786a4a7_1672x941.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Znjb!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a64829f-17d6-4a9e-babc-17361786a4a7_1672x941.png 424w, https://substackcdn.com/image/fetch/$s_!Znjb!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a64829f-17d6-4a9e-babc-17361786a4a7_1672x941.png 848w, https://substackcdn.com/image/fetch/$s_!Znjb!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a64829f-17d6-4a9e-babc-17361786a4a7_1672x941.png 1272w, https://substackcdn.com/image/fetch/$s_!Znjb!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a64829f-17d6-4a9e-babc-17361786a4a7_1672x941.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>When we incorporated GrowthX in 2025, we deliberately ran the work by hand first &#8212; a content marketing agency for clients like Ramp, Lovable, Vercel, Brex and Reddit &#8212; before building the product. That got us to 8 figure revenue and nearly 100 people.</p><p>In June 2026 we launched the first user-facing version of our product. Launching a new product inside a company that size is getting back to seed stage, but with a big team, customers, revenue and everything that comes with them.</p><p>A big engineering team lets us take bold steps. It also means I have to keep reminding myself that the team building this first version should behave like it&#8217;s seed stage.</p><p>I&#8217;ve kept rereading and referencing Paul Graham&#8217;s essays. And I wanted an audio version for my commute.</p><p>I pointed the <a href="https://journal.daniellopes.dev/p/highlights-from-hartmut-esslingers">same pipeline I built for a Computer History Museum oral history</a> at Paul Graham&#8217;s blog to get the 230 essays I want to read again. Here is the first batch, grouped by theme; I will add all of the others over the next few days as they convert &#8212; sharing here in case others find it useful.</p><p><em><mark data-color="#d9ead3" style="background-color: rgb(217, 234, 211); color: rgb(0, 0, 0);">The audio is machine-narrated, and the text is adapted for listening rather than read verbatim. Every episode links to the original, which is the real thing.</mark></em></p><h2>Startups &amp; Founders</h2><p>Whole theme: 13 hours.</p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;b3ecbde9-5e2a-4f3d-94be-fc63bde27cf6&quot;,&quot;duration&quot;:47455.766,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>How to Get Startup Ideas</h3><p>Startup ideas come from problems you already have, not brainstorming sessions. The test: would anyone use a crappy v1 from an unknown two-person team, the way a few thousand Altair owners needed Basic?<br>Duration: 40min, Publish Date: Nov 2012, Post: <a href="https://www.paulgraham.com/startupideas.html">paulgraham.com/startupideas.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;10caf4a6-e65b-498f-9670-8839f45bab97&quot;,&quot;duration&quot;:2420.8718,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>Do Things that Don&#8217;t Scale</h3><p>Startups take off because founders force them to, not because a better product attracts users on its own. Stripe&#8217;s founders set up beta users on the spot, and 10% weekly growth turns 100 users into 14,000 in a year.<br>Duration: 25min, Publish Date: Jul 2013, Post: <a href="https://www.paulgraham.com/ds.html">paulgraham.com/ds.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;4046d101-48b0-4435-a9e4-04368e9a7b71&quot;,&quot;duration&quot;:1472.1829,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>Startup = Growth</h3><p>Growth rate is the one number that defines a startup, and it separates real ones from disguised small businesses. Track it weekly: 5-7% is good, 10% is exceptional, 1% means you haven&#8217;t found it yet.<br>Duration: 30min, Publish Date: Sep 2012, Post: <a href="https://www.paulgraham.com/growth.html">paulgraham.com/growth.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;1373c12e-26be-46ab-8b78-d906c88850d5&quot;,&quot;duration&quot;:1812.4539,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>Schlep Blindness</h3><p>Unconscious avoidance hides the best startup ideas, since founders flinch from tedious problems like payments and build recipe sites instead. Stripe fixed payments after a decade of hackers ignoring it; find your own version by asking what problem you wish someone else would solve.<br>Duration: 5min, Publish Date: Jan 2012, Post: <a href="https://www.paulgraham.com/schlep.html">paulgraham.com/schlep.html</a><br></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;2e943ff5-c918-4755-9f71-3876d0f81023&quot;,&quot;duration&quot;:299.02368,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>Alive or Default Dead?</h3><p>Most startups die from hiring too fast on mediocre growth, not from running out of ideas. Check whether current revenue growth gets you to profitability before the money runs out; Airbnb waited 4 months after Y Combinator to hire its first employee.<br>Duration: 8min, Publish Date: Oct 2015, Post: <a href="https://www.paulgraham.com/aord.html">paulgraham.com/aord.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;4a4338d2-f6b4-48b8-aab0-3bb872bfe29a&quot;,&quot;duration&quot;:509.15265,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>What Happened to Yahoo</h3><p>Yahoo had the money and the traffic to beat Google and blew it by calling itself a media company instead of hiring hackers. Programmers took orders from product managers instead of asking &#8220;what should we do,&#8221; and that killed the talent that would have caught search&#8217;s value before Google did.<br>Duration: 12min, Publish Date: Aug 2010, Post: <a href="https://www.paulgraham.com/yahoo.html">paulgraham.com/yahoo.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;cbf39add-7d01-45da-9c40-73081f123c1f&quot;,&quot;duration&quot;:700.8914,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>Ramen Profitable</h3><p>Ramen profitable means a startup covers only the founders&#8217; living costs, not a real business, but it ends dependence on investors. Google licensed search to Yahoo to get there; the danger is sliding into consulting and calling it a startup.<br>Duration: 11min, Publish Date: Jul 2009, Post: <a href="https://www.paulgraham.com/ramenprofitable.html">paulgraham.com/ramenprofitable.html</a> </p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;819f5bd3-f638-4882-968b-ba6757a2cb4d&quot;,&quot;duration&quot;:640.28735,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>How to Start Google</h3><p>Startups grow out of projects you build because you&#8217;re interested, not assignments you complete because you&#8217;re told. The test for a real idea: something you and your friends would be sad to lose, built by someone who&#8217;s spent years practicing a craft, before ever aiming at a company.<br>Duration: 15min, Publish Date: Mar 2024, Post: <a href="https://www.paulgraham.com/google.html">paulgraham.com/google.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;f9e741bf-2edf-4e9b-b44b-422ddd94c633&quot;,&quot;duration&quot;:917.44653,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>What Microsoft Is this the Altair Basic of?</h3><p>Lame-sounding startups turn into giants; the trick is asking what company this small idea could become, not dismissing it on sight. One founder&#8217;s idea mapped to three separate possible Microsofts, varying by orders of magnitude.<br>Duration: 2min, Publish Date: Feb 2015, Post: <a href="https://www.paulgraham.com/altair.html">paulgraham.com/altair.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;985ae098-71d9-4f2a-8e63-b0c93bd705e0&quot;,&quot;duration&quot;:135.96735,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>The 18 Mistakes That Kill Startups</h3><p>Eighteen distinct mistakes kill startups, but they all funnel into one: not building something users want. Skip the sixth largest startup hub, skip Windows in the 90s, and take VC money only when you can spend it in weeks, not months.<br>Duration: 29min, Publish Date: Oct 2006, Post: <a href="https://www.paulgraham.com/startupmistakes.html">paulgraham.com/startupmistakes.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;80cc7833-0add-47b6-9631-4ea02f8e1d71&quot;,&quot;duration&quot;:1718.5698,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>Change Your Name</h3><p>Not owning the .com of your name signals weakness, even if mobile made domains matter less for actual traffic. Test: 100% of YC&#8217;s top 20 companies by valuation have it, only 66% of the current batch do.<br>Duration: 4min, Publish Date: Aug 2015, Post: <a href="https://www.paulgraham.com/name.html">paulgraham.com/name.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;01d329e0-e55a-487b-a2a9-4575d9b96e6d&quot;,&quot;duration&quot;:251.03673,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>Ideas for Startups</h3><p>Startup ideas are worthless as standalone assertions; they only become real once you treat them as questions to test, not blueprints to follow. Y Combinator won&#8217;t fund single founders because good ideas emerge from friends arguing, not solo brainstorming.<br>Duration: 21min, Publish Date: Oct 2005, Post: <a href="https://www.paulgraham.com/ideas.html">paulgraham.com/ideas.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;a4395620-6e32-48f0-80f9-079e136f3706&quot;,&quot;duration&quot;:1274.5404,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>Don&#8217;t Talk to Corp Dev</h3><p>Corp dev only wants to buy you, and taking the meeting before you&#8217;re ready to sell wrecks morale and distracts you into a bad deal. Ask first: do you want to sell right now, not eventually?<br>Duration: 7min, Publish Date: Jan 2015, Post: <a href="https://www.paulgraham.com/corpdev.html">paulgraham.com/corpdev.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;444ab3e4-6bfc-44f4-bd30-e7a182d1786d&quot;,&quot;duration&quot;:410.2008,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>Mean People Fail</h3><p>Meanness makes you stupid and costs you the best people, so the most successful founders win by building rather than fighting. Startups that get bought for money were never in it to change anything; the ones that keep going are.<br>Duration: 5min, Publish Date: Nov 2014, Post: <a href="https://www.paulgraham.com/mean.html">paulgraham.com/mean.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;96c47353-8596-4e05-a912-b9fb92ca5963&quot;,&quot;duration&quot;:280.50287,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>Relentlessly Resourceful</h3><p>Getting from stuck to unstuck takes resourcefulness, not just persistence, since novel obstacles can&#8217;t be muscled through blindly. The test: ask if you&#8217;re relentlessly resourceful before starting a startup, or recruiting a cofounder.<br>Duration: 6min, Publish Date: Mar 2009, Post: <a href="https://www.paulgraham.com/relres.html">paulgraham.com/relres.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;e7445065-5e5d-488f-8485-62516db95d86&quot;,&quot;duration&quot;:333.55756,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>The Hardest Lessons for Startups to Learn</h3><p>Release something minimal fast, then improve it constantly based on user reactions, because you never know your users well enough to guess right. Wufoo shipped its form builder before the database and got 83,000 users driving a car with no engine.<br>Duration: 26min, Publish Date: Apr 2006, Post: <a href="https://www.paulgraham.com/startuplessons.html">paulgraham.com/startuplessons.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;2c7e5d19-53aa-44d5-accd-ec0fb608b9c3&quot;,&quot;duration&quot;:1577.0122,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>The Ronco Principle</h3><p>Nice is not luck; it is the strategy that wins referrals in a transparent, unpredictable market. Ron Conway got Google, Facebook, and Twitter by being the one investor who never had to fake it.<br>Duration: 4min, Publish Date: Jan 2015, Post: <a href="https://www.paulgraham.com/ronco.html">paulgraham.com/ronco.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;fae6b173-7b15-4a6b-9480-e55e3b65fabb&quot;,&quot;duration&quot;:213.00244,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>What We Look for in Founders</h3><p>Determination and flexibility matter more than raw brainpower; imagination matters more than speed at solving known problems. Airbnb&#8217;s founders paid rent selling Obama and McCain cereal before the &#8220;too crazy&#8221; idea worked.<br>Duration: 4min, Publish Date: Oct 2010, Post: <a href="https://www.paulgraham.com/founders.html">paulgraham.com/founders.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;41c35414-eca7-4c6d-929b-2ea49d7e832e&quot;,&quot;duration&quot;:267.2849,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>A Student&#8217;s Guide to Startups</h3><p>Startups need less to succeed young than you&#8217;d think: what matters is stamina, cheap living, and co-founders you already know, not experience. Y Combinator&#8217;s official advice is to wait until after graduation anyway, because losing &#8220;student&#8221; as an excuse pushes you to try harder.<br>Duration: 35min, Publish Date: Oct 2006, Post: <a href="https://www.paulgraham.com/mit.html">paulgraham.com/mit.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;9a2f7824-9f78-451c-a3d3-26b9b020e1f0&quot;,&quot;duration&quot;:2100.271,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>Be Good</h3><p>Making money is easier than making something great, so build the great thing first and profit follows. Craigslist and early Google prove it: Google ran ad-free for over a year and still won.<br>Duration: 15min, Publish Date: Apr 2008, Post: <a href="https://www.paulgraham.com/good.html">paulgraham.com/good.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;12e8f688-dff3-4bcf-9b7c-d42d265f1bfb&quot;,&quot;duration&quot;:906.24,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>Before the Startup</h3><p>Startups punish faking: you can talk your way past investors, but users only care if the product works. Don&#8217;t start one at 20 &#8212; build genuine expertise first, then let the idea find you, the way a Harvard student built VoIP just to call his girlfriend.<br>Duration: 25min, Publish Date: Oct 2014, Post: <a href="https://www.paulgraham.com/before.html">paulgraham.com/before.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;56e7ffbb-92cd-42dc-90bd-681dacb2ca3f&quot;,&quot;duration&quot;:1517.3485,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>Can You Buy a Silicon Valley? Maybe.</h3><p>Cities can buy a startup hub instead of growing one organically, if they pay startups enough to stay put. A million dollars each to 30 relocated companies is the cheapest real test.<br>Duration: 10min, Publish Date: Feb 2009, Post: <a href="https://www.paulgraham.com/maybe.html">paulgraham.com/maybe.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;df408ea3-40fd-4df9-8ffa-2a9817c0dc7b&quot;,&quot;duration&quot;:614.7657,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>Female Founders</h3><p>Y Combinator funds more female founders than VCs do and helps them beat investor bias, the same tactic that worked for young founders a decade earlier. Current batch: 24% of companies have female founders, up from 9% two years ago.<br>Duration: 12min, Publish Date: Jan 2014, Post: <a href="https://www.paulgraham.com/ff.html">paulgraham.com/ff.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;8e7565ba-c2ba-476f-ac97-5d27749151ed&quot;,&quot;duration&quot;:701.59674,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>Five Founders</h3><p>Steve Jobs, TJ Rodgers, Larry and Sergey, Paul Buchheit, and Sam Altman shaped how founders think about design, candor, hiring, and ambition. One line sums it up: better to make a small number of users love you than a large number kind of like you.<br>Duration: 4min, Publish Date: Apr 2009, Post: <a href="https://www.paulgraham.com/5founders.html">paulgraham.com/5founders.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;2700ea44-e4a5-4b47-8370-ffb7a472329a&quot;,&quot;duration&quot;:252.7347,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>Founder Control</h3><p>Founders keep majority board seats after a series A in a dozen YC-funded companies, following Zuckerberg and Pincus. Board control is not veto power over big decisions, but it means your view of shareholders&#8217; interest wins when opinion splits.<br>Duration: 4min, Publish Date: Dec 2010, Post: <a href="https://www.paulgraham.com/control.html">paulgraham.com/control.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;7f56d688-d7ea-4f2a-925c-bd902fc9e2af&quot;,&quot;duration&quot;:242.10286,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>Founder Mode</h3><p>Founder mode says the standard advice to &#8220;hire good people and give them room&#8221; wrecks companies once you started them yourself. Steve Jobs ran skip-level retreats for Apple&#8217;s 100 most important people, regardless of rank on the org chart.<br>Duration: 7min, Publish Date: Sep 2024, Post: <a href="https://www.paulgraham.com/foundermode.html">paulgraham.com/foundermode.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;8fb4439e-6e07-4e89-8a3c-7329186bfe6a&quot;,&quot;duration&quot;:399.88245,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>Founders&#8217; Accents</h3><p>Accents are not the problem; being unintelligible is. Y Combinator ranked every company by valuation and found the highest-rated CEO with a strong foreign accent came in around 100th place.<br>Duration: 4min, Publish Date: Aug 2013, Post: <a href="https://www.paulgraham.com/accents.html">paulgraham.com/accents.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;932cae3a-dbf8-42a6-a1e1-95bfe152cee1&quot;,&quot;duration&quot;:241.03183,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>Frighteningly Ambitious Startup Ideas</h3><p>Big startup ideas repel people before they attract them, which is why the best ones stay hidden. A new search engine only needs 10,000 hackers to start; email should become a todo-list protocol worth $1000 a month.<br>Duration: 21min, Publish Date: Mar 2012, Post: <a href="https://www.paulgraham.com/ambitious.html">paulgraham.com/ambitious.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;f973663a-ef5f-4ad1-a666-42528c356acb&quot;,&quot;duration&quot;:1272.2938,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>Hiring is Obsolete</h3><p>Undergrads are undervalued because investors can&#8217;t tell which 22-year-old is Bill Gates, and a failed startup at 22 costs nothing. Nine in ten startups fail, but Yahoo&#8217;s Zod Nazem still says he&#8217;d hire the guy whose startup tanked over the guy who took a safe job.<br>Duration: 26min, Publish Date: May 2005, Post: <a href="https://www.paulgraham.com/hiring.html">paulgraham.com/hiring.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;c5a02761-c867-4b23-8945-e0382363ad66&quot;,&quot;duration&quot;:1554.129,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>How Not to Die</h3><p>Half of funded startups get rich just by not dying; the rest quit from discouragement, distraction, or grad school. Stay in contact, keep shipping, and never finish a sentence with &#8220;but we&#8217;re going to keep working on the startup.&#8221;<br>Duration: 10min, Publish Date: Aug 2007, Post: <a href="https://www.paulgraham.com/die.html">paulgraham.com/die.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;2d0e6684-32d0-4540-afcc-bd5ef41e3d71&quot;,&quot;duration&quot;:627.5396,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>How to Start a Startup</h3><p>Startups need three things: good people, something customers want, and low spending. Get all three right and you probably succeed; the &#8220;animal&#8221; test spots the first, and $10,000 seed money got Viaweb the third.<br>Duration: 53min, Publish Date: Mar 2005, Post: <a href="https://www.paulgraham.com/start.html">paulgraham.com/start.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;9638fb66-81b1-4b7b-a612-96cebc8b0bd7&quot;,&quot;duration&quot;:3158.2825,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>Learning from Founders</h3><p>Startups do their best work looking unprofessional: no suits, no clean desks, no polished decks, just people building at 2am. The test for real productivity: could you cut off everything added just to look impressive, the way a car magazine stripped a &#8220;sports&#8221; car down to win the quarter mile.<br>Duration: 5min, Publish Date: Jan 2007, Post: <a href="https://www.paulgraham.com/foundersatwork.html">paulgraham.com/foundersatwork.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;319d7f51-811a-4e37-b2ca-74d50253a21b&quot;,&quot;duration&quot;:281.0253,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>Microsoft is Dead</h3><p>Microsoft stopped being scary around 2005, killed by Google, the web replacing the desktop, broadband, and Apple&#8217;s comeback. They still make money, like IBM, but no startup bothers inviting them to demo day anymore.<br>Duration: 7min, Publish Date: Apr 2007, Post: <a href="https://www.paulgraham.com/microsoft.html">paulgraham.com/microsoft.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;89a9fdac-c9c5-4c26-bb3f-744809f981d2&quot;,&quot;duration&quot;:434.59918,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>Organic Startup Ideas</h3><p>Startup ideas work best when they fix something broken in your own life, not something you guess strangers need. Test it against the Facebook-in-2004 case: nobody called a paper Harvard directory a startup idea, but it was one.<br>Duration: 6min, Publish Date: Apr 2010, Post: <a href="https://www.paulgraham.com/organic.html">paulgraham.com/organic.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;1d4d1abb-a798-4fdd-8249-0f3417240bdd&quot;,&quot;duration&quot;:333.08734,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>Post-Medium Publishing</h3><p>Publishers never sold content, only the format it came in: books, discs, paper. Better journalism didn&#8217;t cost more; The Economist ran 8.1 cents a page against Time&#8217;s 8.6, cheaper for the better read.<br>Duration: 10min, Publish Date: Sep 2009, Post: <a href="https://www.paulgraham.com/publishing.html">paulgraham.com/publishing.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;ebda44c8-b3b2-4b3d-abd9-efe4fceb6a35&quot;,&quot;duration&quot;:599.9804,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>Startups in 13 Sentences</h3><p>Make a few users love you, not many merely satisfied. The test: if you think you&#8217;re 85% there, ask how you&#8217;d know it isn&#8217;t 10%.<br>Duration: 8min, Publish Date: Feb 2009, Post: <a href="https://www.paulgraham.com/13sentences.html">paulgraham.com/13sentences.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;e5ff6adf-03ac-4bfd-b477-8c3122d566ba&quot;,&quot;duration&quot;:461.4792,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>The Airbnbs</h3><p>Airbnb almost died before Y Combinator: a year of no growth, credit cards maxed out, one investor walking out mid-meeting. Three weeks into the batch, weekly fees went $460, $897, $1428 &#8212; ramen profitable at $4000/month, taped to their bathroom mirror.<br>Duration: 6min, Publish Date: Dec 2020, Post: <a href="https://www.paulgraham.com/airbnbs.html">paulgraham.com/airbnbs.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;af6c083e-4a77-42cc-be53-fe0ba57a6353&quot;,&quot;duration&quot;:357.87756,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>The Cliffs Notes - Microsoft is Dead</h3><p>Relevance leads revenue by five or ten years, so a company can be dead long before its balance sheet shows it. Technology companies almost never make comebacks; SAP still makes money, but nobody building new technology worries about it.<br>Duration: 2min, Publish Date: Apr 2007, Post: <a href="https://www.paulgraham.com/cliffsnotes.html">paulgraham.com/cliffsnotes.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;c73d66b4-69d8-407e-aed1-701103c9741b&quot;,&quot;duration&quot;:138.84082,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>The Fatal Pinch</h3><p>Losing money with runway shrinking and no revenue growth, betting on a raise that won&#8217;t come, is how startups die. Fire people, sell instead of code, or ask customers &#8220;what would you pay a lot for&#8221; instead of &#8220;will you buy this.&#8221;<br>Duration: 9min, Publish Date: Dec 2014, Post: <a href="https://www.paulgraham.com/pinch.html">paulgraham.com/pinch.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;4c552f10-b5ca-41f6-9015-10dbcfa9dd8d&quot;,&quot;duration&quot;:532.8457,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>The Other Road Ahead</h3><p>Web-based software beats desktop software because it ships fixes and features instantly instead of once a year. Viaweb ran three to five releases a day, held under ten known bugs at any time, and cost about $5 in server hardware per user.<br>Duration: 68min, Publish Date: Sep 2001, Post: <a href="https://www.paulgraham.com/road.html">paulgraham.com/road.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;6e7c4f30-bc65-4fd6-a8f3-6421da9bddfd&quot;,&quot;duration&quot;:4077.2703,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>The Pooled-Risk Company Management Company</h3><p>Startups sold for a lump sum and startups run for revenue are the same thing at different points on one curve; being profitable just guarantees you the average acquisition-market outcome instead of nothing. The proof: an acquirer is a &#8220;pooled-risk company management company,&#8221; and a public company will pay for yours if you can survive the wait, five years say.<br>Duration: 7min, Publish Date: Jul 2008, Post: <a href="https://www.paulgraham.com/prcmc.html">paulgraham.com/prcmc.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;87182295-f077-4ec8-9aa0-ee92826360d2&quot;,&quot;duration&quot;:419.5004,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>The Reddits</h3><p>Steve and Alexis Reddit&#8217;s real idea was a cellphone fast-food app so bad Y Combinator rejected them, funding what became Reddit instead. It beat Slashdot by dropping human editors, launched in three weeks with a handful of users, and kept growing even through years of bad management.<br>Duration: 6min, Publish Date: Mar 2024, Post: <a href="https://www.paulgraham.com/reddits.html">paulgraham.com/reddits.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;4ff6edf7-2e27-4a3c-9e1e-bc2227c8be48&quot;,&quot;duration&quot;:370.1812,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>The Trouble with the Segway</h3><p>Riding a Segway makes you look smug, not efficient, because you stand still while it does the work. The fix: build one you ride foot-in-front like a skateboard, not standing like a sedan chair.<br>Duration: 2min, Publish Date: Jul 2009, Post: <a href="https://www.paulgraham.com/segway.html">paulgraham.com/segway.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;63e85edb-e54e-4248-8b05-9dc9cc8030ec&quot;,&quot;duration&quot;:133.06775,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>Web 2.0</h3><p>VC money for internet startups now goes toward getting bought, not IPOs, which is why this boom won&#8217;t repeat 1999. Rupert Murdoch&#8217;s $580 million Myspace purchase is only off from bubble math by a factor of 10.<br>Duration: 19min, Publish Date: Nov 2005, Post: <a href="https://www.paulgraham.com/web20.html">paulgraham.com/web20.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;0f25be34-d58e-4d43-ac19-08996f24d594&quot;,&quot;duration&quot;:1149.44,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>What I&#8217;ve Learned from Users</h3><p>Startup problems repeat across companies, but founders rarely see their own clearly enough to rank them. YC&#8217;s summer 2012 batch broke at 80 startups on an O(n2) advising model, forcing a shift to sharded partner groups.<br>Duration: 12min, Publish Date: Sep 2022, Post: <a href="https://www.paulgraham.com/users.html">paulgraham.com/users.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;3307e518-3f83-436d-b474-db51bfd66ec7&quot;,&quot;duration&quot;:746.65796,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>What Startups Are Really Like</h3><p>Cofounders need character and commitment tested under stress, not raw ability, and everything takes 2-3x longer than expected. Persistence beats intelligence; launch the smallest possible version and let users tell you what&#8217;s wrong.<br>Duration: 28min, Publish Date: Oct 2009, Post: <a href="https://www.paulgraham.com/really.html">paulgraham.com/really.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;f7fb48f9-d922-4bbc-ad8c-f8e1e98fb8cc&quot;,&quot;duration&quot;:1681.3976,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>What the Bubble Got Right</h3><p>Yahoo&#8217;s stock hit $200 on earnings partly generated by startups spending their own funding on Yahoo ads, an unintentional Ponzi scheme that still left a real $8 billion company after a 95% crash. Nerds win going forward: Google gets 82 million monthly users and $3 billion in revenue without ever running an ad.<br>Duration: 22min, Publish Date: Sep 2004, Post: <a href="https://www.paulgraham.com/bubble.html">paulgraham.com/bubble.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;838727a8-a701-4723-9753-a3a6874601ac&quot;,&quot;duration&quot;:1295.9347,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>Why It&#8217;s Safe for Founders to Be Nice</h3><p>Nice founders don&#8217;t lose to rapacious ones because growth compounds and extraction rate is just a constant multiplier on the same curve. Extract half as much and you&#8217;re only 15 weeks behind after two years&#8212;optimize growth rate instead, and you pull ahead.<br>Duration: 5min, Publish Date: Aug 2015, Post: <a href="https://www.paulgraham.com/safe.html">paulgraham.com/safe.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;7450ee54-29de-456d-81f6-dfda65f475e4&quot;,&quot;duration&quot;:274.7298,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>Why Startup Hubs Work</h3><p>Startup hubs work because everyone assumes founding a company is normal and useful strangers keep crossing your path. Sean Parker walking up to the Facebook founders in Palo Alto in 2004 is the proof.<br>Duration: 10min, Publish Date: Oct 2011, Post: <a href="https://www.paulgraham.com/hubs.html">paulgraham.com/hubs.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;2e33ecae-d8d8-4efb-9cbe-4a6a9d05eb1b&quot;,&quot;duration&quot;:600.84247,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>Why There Aren&#8217;t More Googles</h3><p>Startups that turn down acquisition offers usually do better, because the willingness to say no is itself the best predictor of success. Google and Facebook stayed independent only because Yahoo and Microsoft lowballed them.<br>Duration: 8min, Publish Date: Apr 2008, Post: <a href="https://www.paulgraham.com/googles.html">paulgraham.com/googles.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;0f9fc483-d9a1-4fa6-8a26-7d8415c487e8&quot;,&quot;duration&quot;:458.18774,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>Why to Move to a Startup Hub</h3><p>Startups do better the more of a startup hub they&#8217;re in, so all else equal, move to the biggest one. Facebook&#8217;s Boston VC passed and admits it &#8220;may turn out to have been a mistake.&#8221;<br>Duration: 8min, Publish Date: Oct 2007, Post: <a href="https://www.paulgraham.com/startuphubs.html">paulgraham.com/startuphubs.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;bb828c49-57f9-4077-b1a1-6f4d1fb945e7&quot;,&quot;duration&quot;:490.63184,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>Why to Not Not Start a Startup</h3><p>Half of the first Y Combinator batch got rich within two years, and zero percent regretted trying. The real filter isn&#8217;t age or experience: Sam Altman was funded at 19, and the fastest way to gain experience is to just start.<br>Duration: 33min, Publish Date: Mar 2007, Post: <a href="https://www.paulgraham.com/notnot.html">paulgraham.com/notnot.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;d778de77-3290-462b-9e5c-76421a6f3e2a&quot;,&quot;duration&quot;:2005.6816,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>Why to Start a Startup in a Bad Economy</h3><p>Recessions don&#8217;t sink startups; founders do, since technology adoption ignores the stock market. Microsoft&#8217;s Basic interpreter shipped into the 1975 recession, and cheap-to-run &#8220;cockroach&#8221; startups survive even when customers cut budgets one at a time.<br>Duration: 6min, Publish Date: Oct 2008, Post: <a href="https://www.paulgraham.com/badeconomy.html">paulgraham.com/badeconomy.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;b8aba552-4866-4c97-b011-8e999e90a0b3&quot;,&quot;duration&quot;:354.63837,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>Why TV Lost</h3><p>Facebook killed TV: people wanted computers to connect with friends, not to watch shows, and piracy trained them to watch there anyway. Synchronicity and locality are dead, so local TV goes with them.<br>Duration: 9min, Publish Date: Mar 2009, Post: <a href="https://www.paulgraham.com/convergence.html">paulgraham.com/convergence.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;db6aba82-5f8a-4961-9d0a-f697eba00b1e&quot;,&quot;duration&quot;:530.2857,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>Why Twitter is a Big Deal</h3><p>Twitter counts as a new messaging protocol, and those almost never appear or catch on. The last ones that stuck were TCP/IP, SMTP, and HTTP.<br>Duration: 1min, Publish Date: Apr 2009, Post: <a href="https://www.paulgraham.com/twitter.html">paulgraham.com/twitter.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;ff1ce908-c7e2-411e-a0d6-c783b361d4ec&quot;,&quot;duration&quot;:64.94041,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>You Weren&#8217;t Meant to Have a Boss</h3><p>Big companies force freedom down to zero as headcount grows; tree structures give each person freedom in inverse proportion to the whole org&#8217;s size. Groups of 8 work, 50 doesn&#8217;t, and Y Combinator founders visibly &#8220;grow inches taller&#8221; within three months of leaving one.<br>Duration: 14min, Publish Date: Mar 2008, Post: <a href="https://www.paulgraham.com/boss.html">paulgraham.com/boss.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;87fe82d1-5832-4c42-8f7e-0eddfa9cb645&quot;,&quot;duration&quot;:841.3779,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><p></p><div><hr></div><p></p><h2>Work, Ambition &amp; Craft</h2><p>Whole theme: 5 hours.</p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;bb00bbb4-2d87-4a2a-b5a0-ed286f0f1db6&quot;,&quot;duration&quot;:19936.053,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>How to Work Hard</h3><p>Talent and hard work aren&#8217;t substitutes; outliers need both, since you can&#8217;t change your talent, so doing great work reduces to working very hard. Bill Gates: &#8220;I never took a day off in my twenties. Not one.&#8221;<br>Duration: 17min, Publish Date: Jun 2021, Post: <a href="https://www.paulgraham.com/hwh.html">paulgraham.com/hwh.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;85050838-2d38-4003-99bb-c115920cbb67&quot;,&quot;duration&quot;:1047.8499,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>How to Do Great Work</h3><p>Ability plus deep interest in something is the whole recipe; everything else is technique for sustaining it. Work in small, evolving versions rather than plans, and track a single test: are you working on what you most want to work on?<br>Duration: 63min, Publish Date: Jul 2023, Post: <a href="https://www.paulgraham.com/greatwork.html">paulgraham.com/greatwork.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;a686beb0-7007-4bde-a89c-ea12d3a2ca7e&quot;,&quot;duration&quot;:3753.6392,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>Maker&#8217;s Schedule, Manager&#8217;s Schedule</h3><p>Meetings cost programmers more than managers, because building anything takes half a day of unbroken time, not an hour. One meeting can break an afternoon in two pieces too small for real work, and even the prospect of it can flatten the morning before it happens.<br>Duration: 6min, Publish Date: Jul 2009, Post: <a href="https://www.paulgraham.com/makersschedule.html">paulgraham.com/makersschedule.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;26729155-7f80-42cc-8b49-8ee0aaa2ce18&quot;,&quot;duration&quot;:364.27756,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>The Other Half of &#8220;Artists Ship&#8221;</h3><p>Every check an organization adds to prevent mistakes has a cost nobody weighs against the benefit, and it falls hardest on the best people, who simply stop showing up. Acquired startup engineers said they&#8217;d trade half the sale price just to release code same-day again.<br>Duration: 8min, Publish Date: Nov 2008, Post: <a href="https://www.paulgraham.com/artistsship.html">paulgraham.com/artistsship.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;2edc39cd-d423-477b-a151-a0e60cd7be40&quot;,&quot;duration&quot;:456.88162,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>What to Do</h3><p>Take care of people and the world, then make good new things. Newness is the test: a copy, however skilled, isn&#8217;t impressive, which is why Archimedes&#8217;s proof about the sphere and cylinder mattered more than repeating it would have.<br>Duration: 9min, Publish Date: Mar 2025, Post: <a href="https://www.paulgraham.com/do.html">paulgraham.com/do.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;610f32a0-db01-4bbe-b4c0-b50b4d7ef51e&quot;,&quot;duration&quot;:525.8449,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>The Anatomy of Determination</h3><p>Determination beats intelligence at building a startup, and it splits into willfulness balanced by discipline, aimed by ambition. Push either force past the other and, like a squeezed melon seed, you spin off sideways instead of flying straight.<br>Duration: 9min, Publish Date: Sep 2009, Post: <a href="https://www.paulgraham.com/determination.html">paulgraham.com/determination.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;7594bdec-2f9f-4979-8150-6db505475640&quot;,&quot;duration&quot;:550.609,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>Richard Hamming: You and Your Research</h3><p>Great work takes years of compound effort, not luck; keep your office door open and spend Friday afternoons only on important problems. Ten to twenty problems you watch for, courage to attack them, and total commitment separate first-class scientists from the merely talented.<br>Duration: 67min, Publish Date: Mar 1986, Post: <a href="https://www.paulgraham.com/hamming.html">paulgraham.com/hamming.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;78afb47d-a007-4bbf-a3d9-9743df53ed13&quot;,&quot;duration&quot;:3999.2163,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>What Doesn&#8217;t Seem Like Work?</h3><p>If a task other people treat as drudgery feels effortless to you, that&#8217;s the work you&#8217;re suited for. His father solved every textbook problem the day the book arrived, and Graham himself likes debugging.<br>Duration: 3min, Publish Date: Jan 2015, Post: <a href="https://www.paulgraham.com/work.html">paulgraham.com/work.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;51de6078-23b8-4a1c-8301-6d49c8eea8d1&quot;,&quot;duration&quot;:152.5551,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>A Project of One&#8217;s Own</h3><p>Working on a project of your own beats working to order, even when it means longer hours and no clear payoff yet. Y Combinator judged applicants by their side projects, not their grades.<br>Duration: 14min, Publish Date: Jun 2021, Post: <a href="https://www.paulgraham.com/own.html">paulgraham.com/own.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;d0c52025-d16b-4c5c-88e8-62fa06047916&quot;,&quot;duration&quot;:830.1976,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>Cities and Ambition</h3><p>Cities send one message that shapes ambition, and you absorb it just by walking around and overhearing conversations. Cambridge pushes intelligence, New York money, Silicon Valley power; picking the right one matters more than willpower, since even a Milanese-born Leonardo never became one.<br>Duration: 20min, Publish Date: May 2008, Post: <a href="https://www.paulgraham.com/cities.html">paulgraham.com/cities.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;66b2a259-e23a-4aa4-ae72-26ad820fccf6&quot;,&quot;duration&quot;:1185.5151,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>How to Do What You Love</h3><p>Work isn&#8217;t supposed to hurt; the goal is finding what you&#8217;d do even without pay. Test it: would you still do the job for free while waiting tables to survive?<br>Duration: 24min, Publish Date: Jan 2006, Post: <a href="https://www.paulgraham.com/love.html">paulgraham.com/love.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;ad88f8b4-6c90-49f5-a87f-d49f69d71c71&quot;,&quot;duration&quot;:1468.8131,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>Disconnecting Distraction</h3><p>Distractions evolve faster than your defenses; the internet replaced TV as the addiction because it still looks like work. Solution: a separate computer across the room for browsing, so the work machine can only be used to work.<br>Duration: 6min, Publish Date: May 2008, Post: <a href="https://www.paulgraham.com/distraction.html">paulgraham.com/distraction.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;1e95213e-e416-4323-8dba-c03200ada5fb&quot;,&quot;duration&quot;:357.5641,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>Early Work</h3><p>Fear of looking lame stops ambitious work before it starts, since early versions always look bad. Fix: treat new ideas as a challenge to your imagination, not a target for criticism, and overestimate their importance on purpose, the way Hardy said good professors do.<br>Duration: 14min, Publish Date: Oct 2020, Post: <a href="https://www.paulgraham.com/early.html">paulgraham.com/early.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;21c69192-1075-48af-9eca-3edaa246d7f8&quot;,&quot;duration&quot;:836.28406,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>Earnestness</h3><p>Interest in the problem itself, not money or fame, drives founders further than any other motive. Nerds get mocked for caring too much in high school; later, that same earnestness makes them the boss.<br>Duration: 10min, Publish Date: Dec 2020, Post: <a href="https://www.paulgraham.com/earnest.html">paulgraham.com/earnest.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;b179da3a-c9f6-485d-833d-478c50307394&quot;,&quot;duration&quot;:577.09717,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>Good and Bad Procrastination</h3><p>The most impressive people procrastinate on small stuff to work on big stuff, avoiding errands like laundry and email to get real work done. Ask what&#8217;s the best thing you could be working on, and why aren&#8217;t you.<br>Duration: 9min, Publish Date: Dec 2005, Post: <a href="https://www.paulgraham.com/procrastination.html">paulgraham.com/procrastination.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;3f8f04c2-f5a8-4d6a-81c3-ab38d376a37e&quot;,&quot;duration&quot;:569.0253,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>How to Lose Time and Money</h3><p>Fortunes rarely get lost through spending, but through investments that don&#8217;t trip the &#8220;self-indulgent&#8221; alarm. Time follows the same pattern: fake work like email dodges that alarm while producing nothing, worse than a wasted day on the sofa.<br>Duration: 4min, Publish Date: Jul 2010, Post: <a href="https://www.paulgraham.com/selfindulgence.html">paulgraham.com/selfindulgence.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;cb63c981-c010-4d01-a41f-caf75aeffe2a&quot;,&quot;duration&quot;:219.27184,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>Six Principles for Making New Things</h3><p>Simple solutions to overlooked problems win because they look unimpressive enough that nobody else bothers to compete for them. Viaweb shipped under 10,000 lines of code with no credit card processing, and Reddit launched with no design at all.<br>Duration: 7min, Publish Date: Feb 2008, Post: <a href="https://www.paulgraham.com/newthings.html">paulgraham.com/newthings.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;10ff6ffa-c0ea-4d00-91bc-0706d3cb68d8&quot;,&quot;duration&quot;:409.1559,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>Superlinear Returns</h3><p>Returns for performance are superlinear, not linear: half as good means zero customers, not half the customers. Growth compounds through exponential growth and thresholds, so track growth rate, not absolute numbers, and follow curiosity over careerism.<br>Duration: 25min, Publish Date: Oct 2023, Post: <a href="https://www.paulgraham.com/superlinear.html">paulgraham.com/superlinear.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;be245fe8-3aee-49ab-afa2-b276291ed23d&quot;,&quot;duration&quot;:1509.7731,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>The Right Kind of Stubborn</h3><p>Persistence and obstinacy look alike from outside but run on different engines: one is attached to the goal, the other to its first idea. The tell is response to pushback: the Collison brothers listen &#8220;with predatory intensity,&#8221; the obstinate just glaze over.<br>Duration: 12min, Publish Date: Jul 2024, Post: <a href="https://www.paulgraham.com/persistence.html">paulgraham.com/persistence.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;62f0d335-19fa-493d-a096-95577a230ea0&quot;,&quot;duration&quot;:698.5404,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>The Top Idea in Your Mind</h3><p>Whatever you&#8217;re not actively controlling becomes what you think about in the shower, and money and disputes hijack that slot faster than anything else. Newton tried to quit publishing entirely after wasting years defending his color theory against critics like Linus.<br>Duration: 6min, Publish Date: Jul 2010, Post: <a href="https://www.paulgraham.com/top.html">paulgraham.com/top.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;84ceb572-c9d4-416c-9748-169e84a57796&quot;,&quot;duration&quot;:382.5894,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>When To Do What You Love</h3><p>Following your interests only pays off at the extremes: barely at all, or wanting to get rich. Bill Gates loved writing software for customers, not just programming; Apple, Google, and Facebook all started as side projects.<br>Duration: 8min, Publish Date: Sep 2024, Post: <a href="https://www.paulgraham.com/when.html">paulgraham.com/when.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;e471645d-73a4-44e1-87a0-fa3ae9361f9e&quot;,&quot;duration&quot;:498.57306,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><p></p><div><hr></div><p></p><h2>Writing &amp; Language</h2><p>Whole theme: 2 hours.</p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;b57a5df9-3784-4572-bd98-15d0f59e28f8&quot;,&quot;duration&quot;:6654.72,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>Writes and Write-Nots</h3><p>Soon almost no one will be able to write, because AI removes the pressure that once forced people to learn. That matters because writing is thinking: &#8220;if you&#8217;re thinking without writing, you only think you&#8217;re thinking.&#8221;<br>Duration: 3min, Publish Date: Oct 2024, Post: <a href="https://www.paulgraham.com/writes.html">paulgraham.com/writes.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;0b59a213-a8f4-4a95-8422-93ed1cf587a7&quot;,&quot;duration&quot;:178.02449,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>The Best Essay</h3><p>The best essay tells you something surprising about the most important topic possible, but real timelessness requires the opposite: writing about things that never get culturally absorbed, like kids overdoing things or adults lying to kids.<br>Duration: 23min, Publish Date: Mar 2024, Post: <a href="https://www.paulgraham.com/best.html">paulgraham.com/best.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;7f5e8112-ad7c-485c-9c87-5f8a3b42bfb0&quot;,&quot;duration&quot;:1387.0759,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>Good Writing</h3><p>Sentences that sound bad usually carry ideas that are wrong, because fixing the awkward rhythm forces you to fix the thinking underneath it. The test: rewrite a paragraph to be one line shorter, and it always gets better, never worse.<br>Duration: 9min, Publish Date: May 2025, Post: <a href="https://www.paulgraham.com/goodwriting.html">paulgraham.com/goodwriting.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;b2b10182-2229-4d07-9245-7b61518e2282&quot;,&quot;duration&quot;:548.4669,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>Writing, Briefly</h3><p>Writing well matters because it generates ideas, not just conveys them. Draft fast, rewrite until 80% of the ideas emerge after you start, and cut without mercy.<br>Duration: 3min, Publish Date: Mar 2005, Post: <a href="https://www.paulgraham.com/writing44.html">paulgraham.com/writing44.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;f968da4a-5fba-4051-9be7-9e0a4c8ebf36&quot;,&quot;duration&quot;:162.71674,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>The Need to Read</h3><p>Writing teaches you how to think, not just how to record thoughts you already had. Complicated, ill-defined problems get solved by writing about them; easy ones don&#8217;t need it.<br>Duration: 2min, Publish Date: Nov 2022, Post: <a href="https://www.paulgraham.com/read.html">paulgraham.com/read.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;319d9dd3-3bcb-48eb-b4fb-37e03981f8d4&quot;,&quot;duration&quot;:143.9347,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>Writing and Speaking</h3><p>Good ideas carry writing but barely matter in speaking, where delivery and audience reactions dominate. One test: transcribe a great talk and you&#8217;ll often find, as Graham did with a famous speaker, that after ten sentences there&#8217;s nothing there.<br>Duration: 6min, Publish Date: Mar 2012, Post: <a href="https://www.paulgraham.com/speak.html">paulgraham.com/speak.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;b7a641e4-ca2a-42e2-a664-b77e4f43e378&quot;,&quot;duration&quot;:387.42203,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>Write Like You Talk</h3><p>Written language is more work to read and gives you the false feeling you&#8217;re saying more than you are. Test: would you say this sentence to a friend, or does it clank?<br>Duration: 4min, Publish Date: Oct 2015, Post: <a href="https://www.paulgraham.com/talk.html">paulgraham.com/talk.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;e67c7662-d721-49de-9bc0-f20acd9b49b6&quot;,&quot;duration&quot;:247.6147,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>How to Write Usefully</h3><p>Useful writing states claims as strongly as possible without going false, then cuts anything not sure enough to survive: no exceptions, no hedged filler. One test: don&#8217;t publish a sentence unless you&#8217;d bet on it, the way Robert Morris won&#8217;t say anything unless it&#8217;s worth hearing.<br>Duration: 16min, Publish Date: Feb 2020, Post: <a href="https://www.paulgraham.com/useful.html">paulgraham.com/useful.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;69b54b22-5739-4889-8fe0-2e0452f6150d&quot;,&quot;duration&quot;:964.6759,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>Putting Ideas into Words</h3><p>Writing exposes gaps in thinking that feel complete until you try to put them into words. Read your own draft as a stranger would, and fix whatever it flags as missing.<br>Duration: 4min, Publish Date: Feb 2022, Post: <a href="https://www.paulgraham.com/words.html">paulgraham.com/words.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;87a60aaa-2bdf-4961-8818-c310ae858b72&quot;,&quot;duration&quot;:263.54938,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>The Age of the Essay</h3><p>Real essays start with a question, not a thesis, and let the answer surprise you along the way. Track what surprises you, since the surprising 1% is where the truth usually hides.<br>Duration: 26min, Publish Date: Sep 2004, Post: <a href="https://www.paulgraham.com/essay.html">paulgraham.com/essay.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;626b2648-e421-4480-9d96-9e4789bb9311&quot;,&quot;duration&quot;:1563.951,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>The List of N Things</h3><p>Lists of n things read easier because their structure is explicit and their points are independent, so a bad one costs you nothing. That ease is also the trap: you can&#8217;t have a new idea bigger than the slot you pre-built for it, like a 5-paragraph essay capping thought at three points.<br>Duration: 7min, Publish Date: Sep 2009, Post: <a href="https://www.paulgraham.com/nthings.html">paulgraham.com/nthings.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;cf4587a8-c90c-4520-ace5-5b1532f65f89&quot;,&quot;duration&quot;:390.42612,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>The Shape of the Essay Field</h3><p>Writing for smart people about important things means writing for the young, since they have the most room left to change their minds. The Selfish Gene rewired how Graham saw evolution; that&#8217;s the kind of surprise to aim for.<br>Duration: 4min, Publish Date: Jun 2025, Post: <a href="https://www.paulgraham.com/field.html">paulgraham.com/field.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;da73de70-e80c-444a-9073-e9ee7a77f466&quot;,&quot;duration&quot;:252.00327,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>Write Simply</h3><p>Simple sentences and ordinary words let ideas reach readers with less friction, so more people read to the end. The test: if a sentence feels clumsy rather than fancy, cut it.<br>Duration: 3min, Publish Date: Mar 2021, Post: <a href="https://www.paulgraham.com/simply.html">paulgraham.com/simply.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;d14846eb-d270-4802-bcb4-bf863213e0be&quot;,&quot;duration&quot;:165.04163,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h2>Ideas, Thinking &amp; Learning</h2><p>Whole theme: 3 hours.</p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;0bda7419-3b62-4899-8650-a52f6ce0d586&quot;,&quot;duration&quot;:11190.857,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>How to Disagree</h3><p>Disagreement has a hierarchy, from name-calling up to refuting someone&#8217;s central point. The test: can you quote the exact passage you think is wrong and say why?<br>Duration: 9min, Publish Date: Mar 2008, Post: <a href="https://www.paulgraham.com/disagree.html">paulgraham.com/disagree.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;f863e477-165a-46c4-9242-6f6201667df6&quot;,&quot;duration&quot;:531.69635,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>How to Think for Yourself</h3><p>Correct isn&#8217;t enough; original ideas only pay off when most people think you&#8217;re wrong, whether you&#8217;re a scientist, an investor, or a startup founder renting airbeds on strangers&#8217; floors.<br>Duration: 21min, Publish Date: Nov 2020, Post: <a href="https://www.paulgraham.com/think.html">paulgraham.com/think.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;b636c505-6de6-4f24-b04e-9416cf71ede6&quot;,&quot;duration&quot;:1257.6914,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>Crazy New Ideas</h3><p>Never dismiss an implausible idea proposed by a reasonable domain expert; ask why instead of arguing, since Copernicus published heliocentrism in 1532 and it took until the mid-1600s to win over astronomers.<br>Duration: 8min, Publish Date: May 2021, Post: <a href="https://www.paulgraham.com/newideas.html">paulgraham.com/newideas.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;81ea384d-7a5b-47b2-88c2-68a36811af85&quot;,&quot;duration&quot;:478.45877,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>Keep Your Identity Small</h3><p>Political and religious arguments go nowhere because both let anyone opine without expertise, and both get absorbed into identity. Test it on programming languages: X-vs-Y debates turn religious the moment people call themselves &#8220;X programmers.&#8221;<br>Duration: 5min, Publish Date: Feb 2009, Post: <a href="https://www.paulgraham.com/identity.html">paulgraham.com/identity.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;216feda7-c9de-4213-8dd1-2a48d7b609d4&quot;,&quot;duration&quot;:316.369,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>The Four Quadrants of Conformism</h3><p>People sort into four types by conformism and aggression, and the aggressively conventional ones&#8212;tattletales as kids, mobs as adults&#8212;cause most of the trouble. Test: only the independent-minded can tell how much of the idea-space has actually been banned.<br>Duration: 12min, Publish Date: Jul 2020, Post: <a href="https://www.paulgraham.com/conformism.html">paulgraham.com/conformism.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;4fc34a52-9e34-41c3-bb9d-8284b9d48acd&quot;,&quot;duration&quot;:726.25635,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>What You (Want to)* Want</h3><p>Wanting isn&#8217;t fully free: you control what you do, but not what you want, and barely what you want to want. Three or four &#8220;want to&#8221;s in, change becomes nearly unimaginable, like a string of 9s approaching 1.<br>Duration: 3min, Publish Date: Nov 2022, Post: <a href="https://www.paulgraham.com/want.html">paulgraham.com/want.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;ea7c18df-4788-447d-b933-5a31fb557316&quot;,&quot;duration&quot;:172.8,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>Being a Noob</h3><p>The more of a noob you feel locally, the less ignorant you actually are globally &#8212; moving to a new country or field makes you feel dumber while making you know more. The discomfort is a hunter-gatherer instinct built for stable problems, not for cryptocurrency.<br>Duration: 2min, Publish Date: Jan 2020, Post: <a href="https://www.paulgraham.com/noob.html">paulgraham.com/noob.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;6401d8f4-5760-4ebb-b4c0-5e75bb4e6250&quot;,&quot;duration&quot;:131.21306,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>Two Kinds of Judgement</h3><p>Selecting a national team of 20 doesn&#8217;t require judging the 20th player accurately, only that the roster ends up good. Most rejections work the same way, so stop treating admissions or hiring decisions like a court case demanding fairness.<br>Duration: 4min, Publish Date: Apr 2007, Post: <a href="https://www.paulgraham.com/judgement.html">paulgraham.com/judgement.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;48205976-d250-42d8-9f91-764b78e78532&quot;,&quot;duration&quot;:262.11264,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>A Way to Detect Bias</h3><p>You can spot bias without seeing the applicant pool: if a selection process discriminates against a group, that group&#8217;s survivors will outperform everyone else. First Round Capital&#8217;s own portfolio showed female-founded startups beating the rest by 63%.<br>Duration: 3min, Publish Date: Oct 2015, Post: <a href="https://www.paulgraham.com/bias.html">paulgraham.com/bias.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;ca5e8d70-189d-47f1-839e-749308b12ed3&quot;,&quot;duration&quot;:205.71428,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>Alien Truth</h3><p>Physics and math would hold for aliens too, but so would less obvious things like Occam&#8217;s razor and the value of controlled experiments. The test for a real philosophical truth: would an intelligent alien accept it too?<br>Duration: 4min, Publish Date: Oct 2022, Post: <a href="https://www.paulgraham.com/alien.html">paulgraham.com/alien.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;8e171d63-7f89-4e8d-afbd-fefc31296545&quot;,&quot;duration&quot;:237.89714,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>Beyond Smart</h3><p>Being smart and having new ideas are different things, and most people conflate them. Test: an obsessive interest in one topic and independent-mindedness matter more than raw intelligence for finding something new.<br>Duration: 8min, Publish Date: Oct 2021, Post: <a href="https://www.paulgraham.com/smart.html">paulgraham.com/smart.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;d83ca5e2-6c35-4771-81a5-cb7dced54b04&quot;,&quot;duration&quot;:485.12,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>Fashionable Problems</h3><p>Working problems everyone agrees are played out hides the most territory left to explore, because talented people avoid looking unfashionable. Try essays, Lisp, or venture funding: find a new angle into a &#8220;done&#8221; field and the payoff scales with its size.<br>Duration: 1min, Publish Date: Dec 2019, Post: <a href="https://www.paulgraham.com/fp.html">paulgraham.com/fp.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;7d380080-e9c6-4163-be65-70e5db0497c1&quot;,&quot;duration&quot;:64.444084,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>How to Be an Expert in a Changing World</h3><p>Beliefs about a changing world go stale, and experts are usually just experts on an earlier version of it. Bet on people, not ideas: earnest, energetic, independent-minded founders like Airbnb&#8217;s got funded despite the idea looking bad.<br>Duration: 6min, Publish Date: Dec 2014, Post: <a href="https://www.paulgraham.com/ecw.html">paulgraham.com/ecw.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;69086f53-0a8f-4b16-abb1-4e095e3b20c8&quot;,&quot;duration&quot;:378.85388,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>How to Do Philosophy</h3><p>Words break down when pushed too far, which is why philosophy chases unanswerable questions instead of useful ones. The fix: judge an idea by whether it makes anyone do something differently, the way &#8220;controlled experiment&#8221; or &#8220;evolution&#8221; already do.<br>Duration: 27min, Publish Date: Sep 2007, Post: <a href="https://www.paulgraham.com/philosophy.html">paulgraham.com/philosophy.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;2038fb3a-d32e-4963-9046-f0b7f408ff2d&quot;,&quot;duration&quot;:1595.6898,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>How to Get New Ideas</h3><p>New ideas come from noticing anomalies at the edge of what you know, not from brainstorming. Get close enough to a field&#8217;s frontier and the gaps become obvious; chase one and it can grow into a whole new area.<br>Duration: 1min, Publish Date: Jan 2023, Post: <a href="https://www.paulgraham.com/getideas.html">paulgraham.com/getideas.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;d453db74-4bba-4d2b-b8d2-cedca8d33b17&quot;,&quot;duration&quot;:53.420406,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>How You Know</h3><p>Forgetting most of what you read doesn&#8217;t mean it was wasted: it compiles into your mental models even after the source vanishes. Reread important books anyway, since the same text compiles differently at different points in your life.<br>Duration: 4min, Publish Date: Dec 2014, Post: <a href="https://www.paulgraham.com/know.html">paulgraham.com/know.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;b458e131-c44b-4133-ab71-d51f1fd08880&quot;,&quot;duration&quot;:221.2049,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>Is It Worth Being Wise?</h3><p>Wisdom is a high average across situations; intelligence is high peaks in a few. Confucius&#8217;s sage stayed calm because his problems had a correct answer, but a mathematician who invents things goes to bed discontented four nights out of five.<br>Duration: 20min, Publish Date: Feb 2007, Post: <a href="https://www.paulgraham.com/wisdom.html">paulgraham.com/wisdom.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;71b8ba14-8cfd-4a87-8fb5-47e361715c99&quot;,&quot;duration&quot;:1206.4392,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>Mark Twain: Corn-pone Opinions</h3><p>A man&#8217;s opinions come from where his bread and butter is, not from independent reasoning. Test it against hoopskirts and historical novels: styles vanish and spread by imitation, never by argument.<br>Duration: 11min, Post: <a href="https://www.paulgraham.com/cornpone.html">paulgraham.com/cornpone.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;1d9c79b9-62ad-448a-b897-119941f36c94&quot;,&quot;duration&quot;:668.5518,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>The Bus Ticket Theory of Genius</h3><p>Great work needs a pointless-seeming obsession, not just talent and grit. Darwin couldn&#8217;t stop cataloging species, Ramanujan filled slates with series for no reason, and Tolkien built an elvish language before writing a word of fiction.<br>Duration: 15min, Publish Date: Nov 2019, Post: <a href="https://www.paulgraham.com/genius.html">paulgraham.com/genius.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;23c4345c-3538-4dbb-9137-ed655c709590&quot;,&quot;duration&quot;:906.89307,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>The Risk of Discovery</h3><p>Famous scientists took real risks that biographies erase by only remembering the bets that paid off. Newton split his time between physics, alchemy, and theology, all equally promising at the time; only one worked.<br>Duration: 1min, Publish Date: Jan 2017, Post: <a href="https://www.paulgraham.com/disc.html">paulgraham.com/disc.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;5b04282c-785f-4eb4-8029-78839b92a639&quot;,&quot;duration&quot;:79.88245,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>What Charisma Is</h3><p>Charisma comes from liking people, not performing for them: uncharismatic politicians smile so voters will like them, charismatic ones smile because they already like the crowd. Clinton reaching over his own Secret Service agents to shake hands is the tell; wanting contact makes people want you back.<br>Duration: 3min, Publish Date: Nov 2004, Post: <a href="https://www.paulgraham.com/recharisma.html">paulgraham.com/recharisma.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;c60f702a-11a5-4914-98db-47d803e392d6&quot;,&quot;duration&quot;:157.9102,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><h3>Why Smart People Have Bad Ideas</h3><p>Founders waste months on their first startup idea because it felt cool, not because customers would pay for it. Ask early: of everything we could build, is this the one people will pay most for?<br>Duration: 18min, Publish Date: Apr 2005, Post: <a href="https://www.paulgraham.com/bronze.html">paulgraham.com/bronze.html</a></p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;0addab1f-eda4-4613-802d-12a143a13f1a&quot;,&quot;duration&quot;:1052.5519,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div>]]></content:encoded></item><item><title><![CDATA[Highlights from Hartmut Esslinger's Oral History]]></title><description><![CDATA[Explore design legend Hartmut Esslinger's oral history: his Apple Snow White win, frog design's business model, and his philosophy on manufacturing-driven design.]]></description><link>https://journal.daniellopes.dev/p/highlights-from-hartmut-esslingers</link><guid isPermaLink="false">https://journal.daniellopes.dev/p/highlights-from-hartmut-esslingers</guid><dc:creator><![CDATA[Daniel Lopes]]></dc:creator><pubDate>Sat, 22 Aug 2026 23:11:35 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/b79e54fa-b04c-4e36-a625-bd77510feeee_1376x768.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!FFTL!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9efd3b6d-d724-4cca-a0e3-2c8f7659799c_1376x768.webp" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!FFTL!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9efd3b6d-d724-4cca-a0e3-2c8f7659799c_1376x768.webp 424w, https://substackcdn.com/image/fetch/$s_!FFTL!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9efd3b6d-d724-4cca-a0e3-2c8f7659799c_1376x768.webp 848w, https://substackcdn.com/image/fetch/$s_!FFTL!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9efd3b6d-d724-4cca-a0e3-2c8f7659799c_1376x768.webp 1272w, https://substackcdn.com/image/fetch/$s_!FFTL!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9efd3b6d-d724-4cca-a0e3-2c8f7659799c_1376x768.webp 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!FFTL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9efd3b6d-d724-4cca-a0e3-2c8f7659799c_1376x768.webp" width="1376" height="768" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9efd3b6d-d724-4cca-a0e3-2c8f7659799c_1376x768.webp&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:768,&quot;width&quot;:1376,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:81476,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/webp&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://journal.daniellopes.dev/i/212343677?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9efd3b6d-d724-4cca-a0e3-2c8f7659799c_1376x768.webp&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!FFTL!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9efd3b6d-d724-4cca-a0e3-2c8f7659799c_1376x768.webp 424w, https://substackcdn.com/image/fetch/$s_!FFTL!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9efd3b6d-d724-4cca-a0e3-2c8f7659799c_1376x768.webp 848w, https://substackcdn.com/image/fetch/$s_!FFTL!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9efd3b6d-d724-4cca-a0e3-2c8f7659799c_1376x768.webp 1272w, https://substackcdn.com/image/fetch/$s_!FFTL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9efd3b6d-d724-4cca-a0e3-2c8f7659799c_1376x768.webp 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p>Since starting GrowthX, I haven&#8217;t had time to read much other than Slack and PRs. The only thing I can consume these days are audiobooks. Everything else piles into a queue of articles and PDFs I keep telling myself I&#8217;ll get to.</p><p>A lot of that queue is <a href="https://computerhistory.org/">Computer History Museum</a> oral histories. I&#8217;ve watched plenty of the video ones, but some of the best interviews are transcript only.</p><p>So I finally coded the workflow I&#8217;d been meaning to build forever. It cleans up the transcript, splits the speakers, gives each of them their own voice, and narrates it with <a href="https://deepgram.com/product/text-to-speech">Deepgram Aura-2</a>, with chapter marks so you can skip around.</p><p>The first one I wanted to listen to was <a href="https://en.wikipedia.org/wiki/Hartmut_Esslinger">Hartmut Esslinger</a>, the founder of frog design and a design legend. After earning their into becoming Apple&#8217;s design partner by winning Apple&#8217;s Snow White competition and defined the look of Apple hardware until Jony Ive&#8217;s translucent iMacs. The Computer History Museum has a <a href="https://www.computerhistory.org/collections/catalog/102743122/">28-page PDF</a>, which came out as 85 minutes of audio across 20 chapters.</p><p></p><div><hr></div><h2>Audio Version of Esslinger&#8217;s Oral History &#128071;</h2><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;f6cbf162-d263-4bf8-8a98-a9dd5566508c&quot;,&quot;duration&quot;:5124.1274,&quot;downloadable&quot;:true,&quot;isEditorNode&quot;:true}"></div><div><hr></div><p></p><h5>Some highlights from my notes</h5><h3>Winning Apple&#8217;s Snow White prize by refusing the brief</h3><p>Apple ran Snow White in 1982 to unify a product line that had grown by accident. Esslinger was running a small studio out of a village in the Black Forest, and got in the door through a party at a former intern&#8217;s house.</p><p>The assumption inside Apple was that the answer looked like Sony, a company he had spent a decade consulting for. He said no. &#8220;That&#8217;s Japanese. This is different. America must be different.&#8221;</p><p>What he pitched instead was &#8220;simple, white, innocent, sexy, and also a bit more radical, a new global brand.&#8221; His argument for why Apple could get away with it: &#8220;There was no real market for the product, none at all, so Apple can do what is right.&#8221;</p><p>Where he thought Apple&#8217;s own designers had gone wrong: &#8220;Olivetti never had a design language. Olivetti had a design philosophy.&#8221;</p><p>He won the competition, then told the in-house team they couldn&#8217;t implement it, because &#8220;the way you do it, you will destroy it in the first second.&#8221; Most of them left.</p><h3>The two million dollar design fee was a manufacturing argument</h3><p>Two million dollars a year from Apple, starting in 1982, for a studio of eight people. The highest fee ever paid to a designer at the time, and he defends it with unit economics rather than craft.</p><p>&#8220;At a million computers you save 100 bucks per computer, that&#8217;s 100 million dollars. So what is a design fee compared to that?&#8221;</p><p>The savings were engineering. Apple had been painting its plastic enclosures. &#8220;You have a piece of plastic, five dollars. You paint it, it&#8217;s 15.&#8221; So frog moved them to unpainted Lexan, coloured all the way through.</p><p>Then zero-draft moulding. Moulded parts normally need slightly angled walls so they can be pulled out of the mould, and that taper is what makes plastic look cheap. He had solved it at Sony with a collapsible core and 16 or 32 mould pieces instead of two or four, which also put more toolmakers in parallel and shipped the part sooner. Cheaper, faster, and it looked like machined steel.</p><p>The Apple account still wasn&#8217;t profitable for frog at first: &#8220;you have to prove what you can do.&#8221;</p><p>Every argument he makes for design in three hours is a manufacturing or P&amp;L argument.</p><h3>A one percent royalty, not fees, is what built frog design</h3><p>In 1974, before Apple, KaVo hired frog to redesign a dental chair. &#8220;It&#8217;s all hostile; it looks like an electric chair. Why not make it friendly?&#8221;</p><p>The CEO loved the work and had no money. They were building about 20 units a year. So Esslinger asked for a royalty instead of a fee. KaVo offered one percent, he took it, and the contract ran to less than a page.</p><p>A year later, at a regional trade show, they sold 200-plus by 11am on the opening day and stopped taking orders because the factory couldn&#8217;t make them. He redesigned it for volume. It sold for more than twenty years at roughly two million a year in license fees.</p><p>That royalty, not the Apple fee, is what paid for the model shop, an early CAD system, and salaries high enough that industrial designers were paid like engineers.</p><h3>A hundred ideas to Steve Jobs, five shipped</h3><p>Richard Sapper designed for IBM for decades, and later did the ThinkPad. Esslinger quotes him: &#8220;I bring them a thousand ideas and they take one. And I try a hundred times and maybe they do it once. What a waste. What a waste.&#8221;</p><p>His own version at Apple: &#8220;we took a hundred ideas to Steve and we made five good ones and co-developed them.&#8221; Fifty times the throughput, same calibre of designer.</p><p>Why in-house teams go nowhere, using Motorola as the example: good designers, but one reported into engineering and another into marketing, with no connection between them, so &#8220;nobody is really held accountable for corporate vision.&#8221;</p><p>And on the companies who ask to be the next Apple: &#8220;everybody wants to be like Apple, but when you tell them what it takes &#8212; budget, perfect models, realistic simulations, absolutely no shortcuts and a huge love for people &#8212; they balk.&#8221;</p><h3>How frog design doubled its team without losing itself</h3><p>Winning Snow White came with a condition: an office in Silicon Valley, near Apple. frog was eight people in a converted garage in the Black Forest, baking models in the kitchen oven.</p><p>So they hired eight more and had each existing person mentor their exact counterpart for three months, role for role. Then they split the doubled team and moved half of it to Campbell, California. After that, people rotated between Germany and California every month, administration included. &#8220;I was really careful not to lose the culture.&#8221;</p><p>He treated a forced doubling as a chance to get better rather than something to survive: &#8220;the challenge is great, but we have to get better.&#8221;</p><p>Nobody was hired into a new office. The office was cloned, then moved. I&#8217;ve done org-doubling worse than this.</p><h3>Thinking big and acting small</h3><blockquote><p>&#8220;People have to think big, but they have to act small.&#8221;</p></blockquote><p>The last thing he says, after three hours.</p><p>To me, a pattern through the interview is the idea of never settling on one altitude. Pitching Apple on a new global brand, then arguing about the taper on a moulded wall, all in the same conversation.</p>]]></content:encoded></item><item><title><![CDATA[EDD: Evals Driven Development]]></title><description><![CDATA[The ideal LLM-dev environment that I wish was easier to do&#8230;]]></description><link>https://journal.daniellopes.dev/p/edd-evals-driven-development</link><guid isPermaLink="false">https://journal.daniellopes.dev/p/edd-evals-driven-development</guid><dc:creator><![CDATA[Daniel Lopes]]></dc:creator><pubDate>Sun, 10 Aug 2025 19:27:54 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/04112ec2-d6ba-4ca7-be72-e3de3b3929ed_1376x768.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong>The Problem:</strong> Don't try to retrofit LLM testing into old paradigms. Testing pyramids, CI/CD gates, deterministic assertions - these were built for a world where <code>f(x) = y</code> every time. LLMs broke that contract.</p><h2>Core</h2><p>Traditional software has bugs. LLM software has <em>behaviors</em>.</p><p>You don't test behaviors - you observe them, measure them, and guide them. This requires a fundamentally different approach.</p><h2>Three Modes of Observation</h2><p><strong>Mode 1: Introspection</strong> The model evaluates itself during generation. Like a writer reviewing their draft before hitting send. Built-in confidence scoring, explanation generation, self-critique loops. This happens at inference time, costs tokens, but provides immediate guardrails.</p><p><strong>Mode 2: Instrumentation</strong> Automated measurement of what actually happened. Response times, token usage, embedding similarities, retrieval success rates. Like application performance monitoring but for AI quality. Runs continuously, at scale.</p><p><strong>Mode 3: Interpretation</strong> Humans make sense of what matters. Not everything can be measured - sometimes you need human judgment on tone, helpfulness, or edge cases. Expensive but irreplaceable for subjective quality and ground truth.</p><h2>What This Looks Like in Practice</h2><p><strong>During Development:</strong></p><ul><li><p>Start with exploration, not test cases - explore what your model can do</p></li><li><p>Capture interesting behaviors as you discover them (the good, bad, and weird)</p></li><li><p>Write expectations, not assertions: "should be empathetic" not "must contain 'sorry'"</p></li><li><p>Build your eval suite backwards - get it working first, then define what "good" means based on real outputs</p></li></ul><p><strong>During Deployment:</strong></p><ul><li><p>Shadow scoring on real traffic before switching</p></li><li><p>Gradual rollout based on confidence thresholds</p></li><li><p>Automatic fallback to previous version if scores drop</p></li><li><p>No binary deploy/rollback - it's a confidence dial</p></li></ul><p><strong>During Operation:</strong></p><ul><li><p>Stream of observations, not error logs</p></li><li><p>Distribution of scores, not pass/fail counts</p></li><li><p>Anomaly detection, not threshold alerts</p></li><li><p>Behavioral drift tracking, not uptime monitoring</p></li></ul><p><strong>During Improvement:</strong></p><ul><li><p>Human labels on strategic samples, not random QA</p></li><li><p>Disagreement cases between evaluators get priority</p></li><li><p>Corrections become test cases automatically</p></li><li><p>Fine-tuning happens on production-validated examples</p></li></ul><h2>Embracing LLM Constraints</h2><p><strong>Embrace Uncertainty:</strong> Stop pretending LLMs are deterministic. Design for confidence intervals, not binary outcomes.</p><p><strong>Compose, Don't Compile:</strong> Evaluators should be Lego blocks - mix and match for your use case. Need safety + factuality + tone? Stack them.</p><p><strong>Optimize for Learning:</strong> Every evaluation should make the system smarter. If it doesn't feed back into improvement, why measure it?</p><p><strong>Human Time is Sacred:</strong> Only escalate to humans when machines disagree or confidence is low. Make their input count by turning it into reusable signals.</p>]]></content:encoded></item><item><title><![CDATA[Prompt engineering in 2026: what still holds up]]></title><description><![CDATA[Role prompting lost its accuracy claim, self-consistency collapsed, chain-of-thought got narrower. Re-scoring 58 techniques against two years of benchmarks]]></description><link>https://journal.daniellopes.dev/p/prompt-engineering-techniques</link><guid isPermaLink="false">https://journal.daniellopes.dev/p/prompt-engineering-techniques</guid><dc:creator><![CDATA[Daniel Lopes]]></dc:creator><pubDate>Sun, 22 Dec 2024 01:23:33 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!63il!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62959865-18c7-4713-aa0c-0e9cdca68db7_768x429.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I wrote this in June 2024, as my notes after reading <a href="https://arxiv.org/pdf/2406.06608">The Prompt Report</a>, a systematic survey that catalogued 33 vocabulary terms and 58 text prompting techniques across in-context learning, decomposition, ensembling and self-criticism. This is the 2026 update.</p><p>That survey was the most complete map of the field, and it was drawn before reasoning models and native tool calling existed. Those two changes, plus a run of 2025-2026 benchmarks, answered the question a taxonomy can&#8217;t: which of the 58 still earn their tokens.</p><p>The bigger change isn&#8217;t in the taxonomy at all. In 2024 prompting was a specialist skill. You wrote prompts if you were building an AI product. Everyone else shipped software without touching one. In 2026 every programmer writes prompts all day.</p><p>So this is a pass back through the research: what the newer studies measured, and where those numbers contradict advice that still gets repeated. Almost every claim is paper-backed or straight from provider documentation, linked inline. </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!63il!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62959865-18c7-4713-aa0c-0e9cdca68db7_768x429.webp" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!63il!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62959865-18c7-4713-aa0c-0e9cdca68db7_768x429.webp 424w, https://substackcdn.com/image/fetch/$s_!63il!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62959865-18c7-4713-aa0c-0e9cdca68db7_768x429.webp 848w, https://substackcdn.com/image/fetch/$s_!63il!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62959865-18c7-4713-aa0c-0e9cdca68db7_768x429.webp 1272w, https://substackcdn.com/image/fetch/$s_!63il!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62959865-18c7-4713-aa0c-0e9cdca68db7_768x429.webp 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!63il!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62959865-18c7-4713-aa0c-0e9cdca68db7_768x429.webp" width="768" height="429" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/62959865-18c7-4713-aa0c-0e9cdca68db7_768x429.webp&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:429,&quot;width&quot;:768,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:7006,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/webp&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://journal.daniellopes.dev/i/153472652?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad1cfae0-c711-451a-b0d2-77f4769a7eb5_1376x768.webp&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!63il!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62959865-18c7-4713-aa0c-0e9cdca68db7_768x429.webp 424w, https://substackcdn.com/image/fetch/$s_!63il!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62959865-18c7-4713-aa0c-0e9cdca68db7_768x429.webp 848w, https://substackcdn.com/image/fetch/$s_!63il!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62959865-18c7-4713-aa0c-0e9cdca68db7_768x429.webp 1272w, https://substackcdn.com/image/fetch/$s_!63il!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62959865-18c7-4713-aa0c-0e9cdca68db7_768x429.webp 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>What changed</h2><ul><li><p><strong>Example count.</strong> Then: more exemplars improve performance, with diminishing returns past 20. Now: it depends on the task. Classification climbs past 250, reasoning saturates at 4-125 then degrades, and one example often scores below zero.</p></li><li><p><strong>Zero-shot.</strong> Then: the fallback when you have no examples. Now: the default. On GSM8K, 8 exemplars bought nothing over zero-shot.</p></li><li><p><strong>Example labels.</strong> Then: whether demonstrations must be strictly valid is unclear. Now: settled. Random labels cost 0-5%; format and label space do the work.</p></li><li><p><strong>Example order.</strong> Then: order can swing accuracy from below 50% to over 90%. Now: unchanged and still unfixed. Demonstrations at the start are worth up to 6 points.</p></li><li><p><strong>Chain-of-thought.</strong> Then: a core reasoning technique. Now: math and symbolic only. 95% of the MMLU gain came from questions containing &#8220;=&#8221;.</p></li><li><p><strong>&#8220;Let&#8217;s think step by step&#8221;.</strong> Then: task-agnostic, works anywhere. Now: deprecated on reasoning models by all three vendors, at 20-80% more response time.</p></li><li><p><strong>Role prompting.</strong> Then: can sometimes improve accuracy on benchmarks. Now: no reliable accuracy gain on current models, and irrelevant persona detail can cost 30 points.</p></li><li><p><strong>Self-consistency.</strong> Then: improves arithmetic, commonsense and symbolic reasoning. Now: collapsed on frontier models, at +1.6 points for 15x the tokens.</p></li><li><p><strong>Tree of Thoughts.</strong> Then: a decomposition technique. Now: still works, at 5-100x the tokens. Batch jobs only.</p></li><li><p><strong>Temperature and top-p.</strong> Then: yours to tune. Now: reasoning models reject them outright.</p></li><li><p><strong>Agents and tool use.</strong> Then: not covered. Now: the loop is an API contract, not a prompt pattern.</p></li><li><p><strong>Writing the prompt.</strong> Then: by hand. Now: optimizers beat reinforcement learning on most tasks, if you have evals.</p></li></ul><h2>What prompt engineering is</h2><p>The working definition is OpenAI&#8217;s: <a href="https://developers.openai.com/api/docs/guides/prompt-engineering">&#8220;the process of writing effective instructions for a model, such that it consistently generates content that meets your requirements.&#8221;</a> The word doing the work is <em>consistently</em>. Getting one good answer out of a model is easy. Getting the same quality on the next thousand inputs is the job.</p><p>The smallest version of the whole discipline, from the <a href="https://www.promptingguide.ai/introduction/examples">Prompt Engineering Guide</a>:</p><pre><code><code>Classify the text into neutral, negative or positive.
Text: I think the vacation is okay.
Sentiment: neutral
Text: I think the food was okay.
Sentiment:</code></code></pre><p>Output: <code>neutral</code>. One line of instruction, one worked example, one input. The model already knows what sentiment is. The example is there to stop it answering in a paragraph.</p><p>Context engineering is the wider frame. Anthropic&#8217;s <a href="https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents">line</a> is that prompt engineering covers &#8220;methods for writing and organizing LLM instructions for optimal outcomes,&#8221; while context engineering covers curating everything else that lands in the window at inference time: retrieved documents, tool definitions, memory, history. Karpathy&#8217;s <a href="https://www.dbreunig.com/2025/06/25/prompts-vs-context.html">version</a> is &#8220;filling the context window with the right information for the next step.&#8221; For a single-turn feature the prompt is most of the game. Inside an agent it&#8217;s a subset.</p><h2>Prompting is part of the development cycle now</h2><p>A <code>SKILL.md</code> for Claude is a prompt. So is the <code>CLAUDE.md</code> at the root of a project, the description on every tool you hand an agent, every subagent definition in a Claude Agent SDK pipeline, the goal you hand a loop, and the <code>.prompt</code> files in <a href="https://output.ai">Output</a>. None of those are chat. They ship, they get reviewed, and they break on upgrade.</p><p>Which is the part people still underrate. A <a href="https://arxiv.org/html/2507.05573">2025 migration case study</a> found prompts stabilized for GPT-4-32k passing at only 98% on GPT-4.1 and 97.3% on GPT-4.5-preview. Prompts rot like dependencies, and nothing in CI notices unless you wrote the eval.</p><h2>Anatomy, and the one part that&#8217;s a trust boundary</h2><p>Instruction with a definition of done, context, delimited input, output schema. That decomposition is old news, and OpenAI&#8217;s reasoning guidance still puts it well: <a href="https://developers.openai.com/api/docs/guides/reasoning">&#8220;avoid vague instructions by defining what counts as done.&#8221;</a> Here it is with all four parts labelled:</p><pre><code><code># Identity                          &lt;- role, one sentence
You are a support triage assistant for a B2B billing product.

# Instructions                      &lt;- instruction, with a definition of done
Assign exactly one category from the list. Output the category name only,
lowercase, no punctuation. If the ticket matches none, output "other".

# Categories                        &lt;- context the model can't infer
billing_dispute | refund_request | plan_change | access_issue | other

# Ticket                            &lt;- the input, delimited
&lt;ticket&gt;
Charged twice for the October invoice, need one reversed.
&lt;/ticket&gt;</code></code></pre><p>Output: <code>billing_dispute</code>. Those delimiters around the ticket are doing real work. They tell the model where your instructions stop and a stranger&#8217;s text begins.</p><p>The part worth arguing about is where each piece goes. System and developer messages carry higher privilege in the <a href="https://openai.com/index/the-instruction-hierarchy/">instruction hierarchy</a> OpenAI trains models to respect. Role, rules and output format go there. Untrusted content goes in user messages or tool results, never in a developer message: <a href="https://developers.openai.com/api/docs/guides/agent-builder-safety">OpenAI&#8217;s agent safety guidance</a> is explicit about not putting untrusted variables there. The message-role split is an access-control decision, not formatting.</p><p>Ordering is the part that stopped being portable. Anthropic says to <a href="https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/claude-prompting-best-practices">put long documents at the top, above your query</a>, and claims it &#8220;improves performance across all models.&#8221; Google <a href="https://ai.google.dev/gemini-api/docs/prompting-strategies">says the same</a>: all context first, question last. OpenAI&#8217;s general guide puts context near the end, but the <a href="https://developers.openai.com/cookbook/examples/gpt4-1_prompting_guide">GPT-4.1 guide</a> recommends instructions both before <em>and</em> after a long document. Three vendors, three answers. Pick per model and measure.</p><h3>Role prompting got quietly demoted</h3><p>&#8220;You are an expert X&#8221; was sold as an accuracy technique. It isn&#8217;t one any more, and the vendors have moved without announcing it. OpenAI&#8217;s o3 guidance scopes role prompting to <a href="https://developers.openai.com/cookbook/examples/o-series/o3o4-mini_prompting_guide">&#8220;setting the base behavior, tone and outlining the set of actions that are possible.&#8221;</a> Anthropic&#8217;s Claude Opus 4.6 tutorial goes further: <a href="https://claude.com/resources/tutorials/get-the-most-from-claude-opus-4-6">&#8220;Skip the role setting... It infers the appropriate level of expertise from the task and context you provide.&#8221;</a></p><p>The research is why. A <a href="https://arxiv.org/pdf/2512.05858">Wharton study</a> found no expert or low-knowledge persona that reliably improved GPQA Diamond across six models, and no significant gain on MMLU-Pro for five of six. <a href="https://aclanthology.org/2025.emnlp-main.1364/">Peer-reviewed work</a> found expert personas usually neutral, and models &#8220;highly sensitive to irrelevant persona details, with performance drops of almost 30 percentage points.&#8221; A <a href="https://arxiv.org/html/2607.17420">2026 preprint</a> measured a librarian persona dropping mean correctness on Claude Opus from 0.92 to 0.67.</p><p>Keep the role sentence for tone and scope. Don&#8217;t expect it to make the answers more correct.</p><h2>The prompt-writing checklist</h2><p>When a prompt underperforms, the cause is usually somewhere on this list and not in the technique.</p><ol><li><p><strong>State the task and what &#8220;done&#8221; looks like.</strong> Not &#8220;summarize this&#8221; but &#8220;three bullets, under 20 words each, no preamble.&#8221;</p></li><li><p><strong>Say what to do, not only what to avoid.</strong> Negative instructions aren&#8217;t testable.</p></li><li><p><strong>Delimit every piece of input</strong> with XML tags, Markdown headings, or <code>"""</code>. Pick one convention and hold it.</p></li><li><p><strong>Put the output format in the system or developer message</strong>, then enforce it at the API with structured outputs where the schema matters.</p></li><li><p><strong>One role sentence, task-specific.</strong> No stacked adjectives.</p></li><li><p><strong>Static content first, variable content last</strong> so prompt caching can hit the prefix.</p></li><li><p><strong>Show it to a colleague with no context.</strong> Anthropic&#8217;s golden rule: if they&#8217;d be confused, so is the model.</p></li></ol><h2>The foundational techniques, re-scored</h2><h3>Zero-shot is the default, not the baseline</h3><p>A <a href="https://aclanthology.org/2025.findings-emnlp.729.pdf">peer-reviewed 2025 paper</a> put Qwen2.5-72B-Instruct on GSM8K at 95.83 zero-shot with corrected answer extraction, against 95.75 with 8-shot exemplars. The examples bought nothing.</p><p><strong>One example is the count most likely to make things worse.</strong> GPT-4o-mini on AG News scored 0.8446 F1 at zero-shot, dropped to 0.8248 at one shot, and only passed its own baseline at two (<a href="https://arxiv.org/html/2607.22969v1">arXiv:2607.22969</a>). GPT-5 on biomedical QA does the same thing: 0.762 zero-shot, 0.737 at one shot, 0.768 at five (<a href="https://arxiv.org/pdf/2509.04462">arXiv:2509.04462</a>). If you shipped a one-shot prompt without testing zero-shot, you may have paid tokens to lose accuracy.</p><p>Start zero-shot with an explicit output format. Add machinery when your evals show a gap, not in advance.</p><h3>Few-shot examples are versioned config</h3><p>Two to five labeled pairs, for patterns that are easier to show than to describe: a house style for summaries, an odd label taxonomy. Anthropic is the only vendor that publishes a number, and it&#8217;s <a href="https://docs.anthropic.com/en/docs/build-with-claude/prompt-engineering/multishot-prompting">&#8220;3-5 examples for best results.&#8221;</a> OpenAI says &#8220;a handful.&#8221; Google says experiment, and to <a href="https://ai.google.dev/gemini-api/docs/prompting-strategies">&#8220;always include few-shot examples.&#8221;</a></p><p>What examples teach is narrower than most people assume. Replace the gold labels in your demonstrations with random ones and <a href="https://aclanthology.org/2022.emnlp-main.759/">accuracy falls 0-5% absolute</a>. You can watch it happen:</p><pre><code><code>This is awesome! // Negative
This is bad! // Positive
Wow that movie was rad! // Positive
What a horrible show! //</code></code></pre><p>Output: <code>Negative</code>. Correct, despite every label above it being wrong. The examples transmitted the label space and the <code>//</code> format, not the answers. Strip the format and you do worse than no examples at all.</p><p>The fragility is the story. The accuracy gap between demo-selection algorithms reached <a href="https://arxiv.org/html/2410.23099">45% on MRPC</a>. Moving demonstrations from the front of a prompt to the back <a href="https://aclanthology.org/2025.emnlp-main.1503/">flipped over 30% of QA predictions</a> in a 2025 study, without improving correctness. Google warns that <a href="https://ai.google.dev/gemini-api/docs/prompting-strategies">too many examples</a> cause overfitting, and examples buried mid-prompt hit the <a href="https://aclanthology.org/2024.tacl-1.9/">&#8220;lost in the middle&#8221;</a> positional problem.</p><p>Three inputs that all look like cosmetics (which examples, how many, where) move accuracy more than most model swaps do. Formatting alone is in the same range: researchers who changed nothing else measured GPT-3.5-turbo differences of <a href="https://arxiv.org/html/2411.10541">up to 40% on code translation</a>. Version the examples, diff them, cover them with evals.</p><p>Two rules with numbers behind them. Put demonstrations at the <strong>start</strong>: best position across ten model families, worth up to 6 points, and it puts the stable text where the cache can reach it. And never sort examples by label: at 1,169 shots on Clinic-150 that cost <a href="https://arxiv.org/html/2405.00200v1">25.7 points</a>.</p><h3>Chain-of-thought is mostly a math-formatting effect</h3><p>The technique arrived twice. <a href="https://arxiv.org/abs/2201.11903">The first version</a> needed eight hand-written reasoning chains per task, which is real authoring work for one prompt. <a href="https://arxiv.org/abs/2205.11916">Four months later</a>, most of that gain turned out to be free: five words appended to the question, <em>Let&#8217;s think step by step</em>. On text-davinci-002 that took MultiArith from 17.7% to 78.7% and GSM8K from 10.4% to 40.7%, with no examples at all.</p><p>Their Figure 1 is still the clearest before-and-after:</p><blockquote><p>A juggler can juggle 16 balls. Half of the balls are golf balls, and half of the golf balls are blue. How many blue golf balls are there?</p></blockquote><p>Without the trigger the model answers <code>8</code>. It halves once and stops. With it: &#8220;There are 16 balls in total. Half of the balls are golf balls. That means that there are 8 golf balls. Half of the golf balls are blue. That means that there are <strong>4</strong> blue golf balls.&#8221;</p><p>CoT pays when the answer needs two or more steps that depend on each other, and answering directly collapses them into one.</p><p>A <a href="https://arxiv.org/html/2409.12183">meta-analysis of more than 100 papers</a> put it at +14.2 pp on symbolic reasoning, +12.3 pp on math, and no meaningful gain on commonsense tasks. 95% of CoT&#8217;s total MMLU gain came from questions containing &#8220;=&#8221; in the question or output.</p><p>Where it works, it&#8217;s decisive. <a href="https://arxiv.org/html/2608.09942">+59.9 pp on GSM8K for Llama-3.1-8B-Instruct</a>, and Qwen-2.5-7B-Instruct went from 23.1% to 91.1% on GSM8K in the same 2026 study.</p><p>Where it doesn&#8217;t, it costs you. The same Qwen model dropped 28.7 points on HumanEval code generation. Forcing explicit steps cut o1-preview accuracy by <a href="https://arxiv.org/html/2410.21333v1">36.3% absolute</a> on implicit-learning tasks. On reasoning models, prompted CoT bought small GPQA gains for 20-80% more response time, and <a href="https://arxiv.org/html/2506.07142">35-600% longer responses</a> on non-reasoning models.</p><p>Use it for math and symbolic work on non-reasoning models. On reasoning models, use the native control instead: <a href="https://ai.google.dev/gemini-api/docs/gemini-3">Gemini 3 guidance</a> says to replace CoT prompting with <code>thinking_level: 'high'</code> and simplified prompts.</p><p>One thing to know before you show a reasoning trace to anyone. Causal mediation across twelve models found GPT-4 changed its answer only <a href="https://aclanthology.org/2024.findings-emnlp.882/">30% of the time</a> when its reasoning chain was swapped for a perturbed one. CoT changes accuracy; it does not give you an audit trail.</p><h2>The advanced techniques, and what they cost</h2><h3>Tree of Thoughts belongs in batch jobs</h3><p><a href="https://arxiv.org/abs/2305.10601">Tree of Thoughts</a> branches several candidate thoughts per step, scores them, and searches with BFS or DFS. Game of 24 with GPT-4: 74% success against 4.0% for CoT.</p><p>The appendix prices it at 0.47 for best-of-100 CoT, and the authors say it <a href="https://arxiv.org/html/2305.10601v2">&#8220;could require 5-100 times more generated tokens than CoT&#8221;</a> depending on the search setup. My judgment, not a paper&#8217;s: batch jobs on search-like problems, planning and constrained generation. I&#8217;ve never found a user-facing path where the latency was acceptable, and I don&#8217;t have a controlled benchmark behind that.</p><h3>ReAct survived as a loop, not as a parser</h3><p><a href="https://arxiv.org/html/2210.03629v3">ReAct</a> interleaves Thought &#8594; Action &#8594; Observation: 71% task success on ALFWorld against 45% for action-only prompting.</p><p>In 2026 the loop is an API contract. The assistant turn carries the thought as text and the action as a structured block:</p><pre><code><code>{
  "stop_reason": "tool_use",
  "role": "assistant",
  "content": [
    { "type": "text",
      "text": "I'll check the current weather in San Francisco for you." },
    { "type": "tool_use",
      "id": "toolu_01A09q90qw90lq917835lq9",
      "name": "get_weather",
      "input": { "location": "San Francisco, CA", "unit": "celsius" } }
  ]
}</code></code></pre><p>You run the tool and send the observation back as a user message, keyed to the call:</p><pre><code><code>{ "role": "user",
  "content": [{ "type": "tool_result",
    "tool_use_id": "toolu_01A09q90qw90lq917835lq9",
    "content": "15 degrees" }] }</code></code></pre><p>Failures go back the same way with <code>"is_error": true</code> rather than being swallowed; the model recovers better from a visible error than from a silent one. Loop while <code>stop_reason</code> is <code>tool_use</code>, exit on <code>end_turn</code>. <a href="https://platform.claude.com/docs/en/agents-and-tools/tool-use/how-tool-use-works">Anthropic&#8217;s docs</a> never say &#8220;ReAct&#8221;; the mapping is structural. If you are still regexing <code>Action:</code> out of free text, that&#8217;s a 2023 artifact.</p><p>The Thought half is the contested part. A <a href="https://mlanthology.org/tmlr/2025/bhambri2025tmlr-think/">peer-reviewed 2025 study</a> found performance <a href="https://mlanthology.org/tmlr/2025/bhambri2025tmlr-think/">&#8220;is minimally influenced by the interleaved reasoning trace.&#8221;</a> <a href="https://arxiv.org/html/2410.02810v2">StateAct</a> scored 27.80% on WebShop with the thought step removed against ReAct&#8217;s 17.80%. <a href="https://arxiv.org/html/2605.09252v2">When2Tool</a> is the alarming one: adding Reason-then-Act dropped Llama-3.1-8B tool accuracy from 79.5% to 31.2%.</p><p>It cuts the other way too. Anthropic&#8217;s <a href="https://www.anthropic.com/engineering/claude-think-tool">think tool</a> with tuned prompting hit 0.584 on &#964;-bench Airline against a 0.332 baseline, beating native extended thinking at 0.412. <a href="https://arxiv.org/html/2509.18076">ToolGT</a> found structured templates beat free-form CoT which beat no thought at all.</p><p>Both results can be true. Models trained for native tool calling already know what to call, so an extra verbal layer is at best neutral. Text-formatted agents still benefit. Test with the trace and without it rather than assuming.</p><h3>Self-consistency has collapsed on frontier models</h3><p><a href="https://arxiv.org/abs/2203.11171v4">Self-consistency</a> samples several CoT paths at nonzero temperature and takes the majority answer. On PaLM-540B and GSM8K that went from 56.5 to 74.4 at 40 paths, with 5-10 paths capturing most of it. <a href="https://arxiv.org/html/2401.10480">Early-stopping variants</a> matched 40-sample accuracy on GSM8K at an average of 14.65 samples.</p><p>Now run it on a frontier model. Gemini-2.5-Pro on MATH-500 goes from <a href="https://arxiv.org/html/2511.00751v2">98% at one path to 99.6% at 15</a>. A 1.6-point gain for roughly 15&#215; the tokens.</p><h3>RAG is the cheap option, not just the grounded one</h3><p>The grounding case is well known: in the <a href="https://aclanthology.org/anthology-files/anthology-files/pdf/findings/2025.findings-emnlp.849.pdf">XRAG benchmark</a>, GPT-4o went from 6.30% accuracy without retrieval to 75.40% with oracle retrieval.</p><p>The cost case gets skipped. The <a href="https://arxiv.org/html/2606.20898v1">Token Tax study</a> priced long-context prompting at ~4.50 for semantic RAG on the same manufacturing benchmark. Roughly 26&#215; for stuffing the window instead of retrieving into it.</p><p>One failure mode to measure for: a <a href="https://link.springer.com/article/10.1007/s10994-026-07121-y">2026 Springer benchmark</a> found hybrid retrieval sometimes increased hallucination in smaller models even as retrieval recall improved. Score faithfulness, not just recall.</p><h3>Let the optimizer write it</h3><p>The newest option here is to stop writing the prompt yourself.</p><p><a href="https://arxiv.org/abs/2507.19457v2">GEPA</a> runs a candidate prompt on a minibatch, captures the traces and whatever the environment said back (compiler errors, judge notes), and shows a reflection model the whole tuple so it can propose a revision. It keeps a Pareto frontier of candidates that win on at least one example rather than one global best. On GPT-4.1 Mini across six benchmarks it beat MIPROv2 by more than double: +12.19 aggregate against +5.64. Against GRPO reinforcement learning it won five of six tasks, by up to 19 points, using up to 35&#215; fewer rollouts.</p><p>Prompt evolution now beats reinforcement learning on most tasks at a fraction of the sample cost, which was not true in 2024.</p><p>The prerequisites are the catch, and they&#8217;re the same three things evals need: a metric that scores an example, a representative dataset, and a test set you haven&#8217;t touched. Without them it optimizes noise. Across 72 optimization runs on Claude Haiku 4.5, <a href="https://arxiv.org/html/2604.14585v2">49% scored below zero-shot</a>: a coin flip, driven by eval sets too small to measure with.</p><p>Three more things worth knowing before you reach for it. More data is not better: Decagon found peak performance at <a href="https://decagon.ai/blog/optimizing-gepa-for-production">20 samples</a>, with 500 costing 2% accuracy and 75% prompt bloat. The reflection model has to be strong, since a weak one returns your seed prompt nearly unchanged. And it optimizes around bugs rather than fixing them. GEPA drove a <a href="https://aclanthology.org/2026.acl-srw.8.pdf">defective GSM8K seed</a> from 23.81% down to 13.50% while the root cause sat there untouched.</p><p>We haven&#8217;t put this in production at GrowthX. Our prompts change faster than a compile cycle would pay for, which is a statement about our release cadence rather than about GEPA.</p><h2>Sampling settings: mostly stop tuning them</h2><p><strong>OpenAI.</strong> Temperature 0-2, no stated default, no top_k support. Reasoning control is <code>reasoning_effort</code>.</p><p><strong>Anthropic.</strong> Temperature 0.0-1.0, default 1.0, top_k documented for advanced use only. Reasoning control is <code>effort</code>, the adaptive-thinking parameter.</p><p><strong>Google Gemini.</strong> Temperature 0.0-2.0, default 1.0, top_k supported and fixed at 64 on Gemini 2.5 Pro. Reasoning control is <code>thinkingLevel</code> or <code>thinkingBudget</code>.</p><p>On classic models the advice is unchanged: 0-0.3 for extraction, classification and function calling, 0.7-1.0 for creative generation, and alter temperature or top_p <a href="https://developers.openai.com/api/reference/resources/chat">&#8220;but not both.&#8221;</a> OpenAI&#8217;s cookbook uses <code>temperature=0</code><a href="https://developers.openai.com/cookbook/examples/structured_outputs_intro"> for function calling and 0.2 for structured summarization</a>.</p><p>On reasoning models, the knobs are being taken away. Anthropic&#8217;s Claude Opus 5 / Sonnet 5 generation returns a <a href="https://platform.claude.com/docs/en/build-with-claude/thinking">400 error on non-default temperature, top_p, or top_k</a>; you steer with the adaptive-thinking <code>effort</code> parameter. Google&#8217;s <a href="https://ai.google.dev/gemini-api/docs/generate-content/gemini-3">Gemini 3 guidance</a> recommends keeping temperature &#8220;at its default value of 1.0&#8221; and warns that lowering it can cause looping and degraded reasoning. On reasoning models there is close to nothing left to tune.</p><p>The caveat that bites people writing tests: Anthropic documents that <a href="https://docs.anthropic.com/en/api/messages">&#8220;even with temperature of 0.0, the results will not be fully deterministic,&#8221;</a> and Google <a href="https://cloud.google.com/vertex-ai/generative-ai/docs/multimodal/content-generation-parameters">says the same</a>. Exact-match assertions on model output will flake.</p><h2>Prompting inside an agent loop</h2><p>Single-turn prompting is one shot at getting the wording right. Agent prompting has to survive dozens of iterations, each one putting tool output back into the window.</p><ul><li><p><strong>Tool descriptions are prompt engineering.</strong> Anthropic calls them <a href="https://platform.claude.com/docs/en/agents-and-tools/tool-use/define-tools">&#8220;by far the most important factor in tool performance&#8221;</a> and asks for 3-4 sentences minimum. The evidence backs the emphasis: renaming functions to <code>func_N</code> <a href="https://arxiv.org/html/2506.11266v2">significantly drops performance</a>, and tools with edited descriptions get <a href="https://arxiv.org/abs/2505.18135">over ten times more usage</a>. OpenAI&#8217;s version is the intern test: could a human use this function given only what you gave the model? Say when to use a tool and when not to; hedged instructions like <code>"If in doubt, use [tool]"</code> cause <a href="https://docs.anthropic.com/en/prompt-library/library">overtriggering</a>.</p></li><li><p><strong>Make invalid states unrepresentable.</strong> Enums for finite sets, <code>user_id</code> not <code>user</code>, documented ranges. Turn on strict mode, and note it disables parallel tool calls.</p></li><li><p><strong>Narrow the mandate per step.</strong> OpenAI&#8217;s Atlas hardening guidance says to <a href="https://openai.com/index/hardening-atlas-against-prompt-injection/">&#8220;avoid overly broad prompts like &#8216;review my emails and take whatever action is needed.&#8217;&#8221;</a> Broad mandates compound errors across steps and widen the injection surface.</p></li><li><p><strong>Curate state, don&#8217;t accumulate it.</strong> Decide at each step what history and retrieval results enter the window, and filter tool output the same way.</p></li><li><p><strong>Tool output is untrusted input.</strong> Anything a tool fetched from a third party is attacker-controlled text arriving inside your loop.</p></li></ul><h2>Frameworks are checklists, not engineering</h2><p>Three have published provenance. <strong>CLEAR</strong> (Leo S. Lo, <em><a href="https://www.sciencedirect.com/science/article/pii/S0099133323000599?via%3Dihub">Journal of Academic Librarianship</a></em><a href="https://www.sciencedirect.com/science/article/pii/S0099133323000599?via%3Dihub">, 2023</a>) is Concise, Logical, Explicit, Adaptive, Reflective, and works as a review rubric. <strong>PROMPT Design</strong> (Sarah Hartman-Caverly, <a href="https://sites.psu.edu/digitalshred/2024/02/13/prompt-design-framework-and-worksheet/">Penn State, 2024</a>) is a fill-in-the-blanks scaffold for non-engineers; the academic <a href="https://eber.uek.krakow.pl/index.php/eber/article/download/2142/863">AI PROMPT framework</a> covers similar ground with more emphasis on delimiting elements and token length. <strong>PASTAS</strong> (Lo again, <em><a href="https://muse.jhu.edu/pub/1/issue/57157">portal: Libraries and the Academy</a></em><a href="https://muse.jhu.edu/pub/1/issue/57157">, 2026</a>) was written for the agentic era, and its Tools and Safeguards items map onto the two sections above.</p><p>They help a team remember requirements. They don&#8217;t replace measuring: a CLEAR-compliant prompt that fails your evals is still a failed prompt.</p><h2>Fine-tuning is still the last resort</h2><p>Every provider now documents the same sequence: evals, prompting, RAG for external knowledge, fine-tuning when prompting hits a measured ceiling. OpenAI&#8217;s model-optimization guide says <a href="https://developers.openai.com/api/docs/guides/model-optimization">&#8220;the prompt engineering process may be all you need,&#8221;</a> and its fine-tuning platform is winding down, with existing users able to create training jobs only &#8220;for the coming months.&#8221;</p><p>The thresholds worth holding to:</p><ul><li><p><strong>Volatility.</strong> Microsoft&#8217;s split is <a href="https://learn.microsoft.com/en-us/azure/developer/ai/augment-llm-rag-fine-tuning">dynamic content &#8594; RAG, stable content &#8594; fine-tuning</a>. Hamel Husain&#8217;s version: <a href="https://hamel.dev/blog/posts/fine_tuning_valuable.html">&#8220;fine-tuning works best to learn syntax, style and rules whereas RAG works best to supply the model with context or up-to-date facts.&#8221;</a></p></li><li><p><strong>Example count.</strong> OpenAI recommends <a href="https://developers.openai.com/api/docs/guides/supervised-fine-tuning">50 well-crafted demonstrations</a> for SFT; a <a href="https://aclanthology.org/2025.emnlp-main.9/">peer-reviewed 2025 study</a> puts the classification break-even near 100 labeled examples. At 20-40, Jason Liu argues you are <a href="https://jxnl.co/writing/2025/01/22/10-foot-guns-in-fine-tuning-and-few-shots/">better off with prompt caching</a>.</p></li><li><p><strong>Good enough.</strong> The applied-llms.org rule: <a href="https://applied-llms.org/">&#8220;if prompting gets you 90% of the way there, then finetuning may not be worth the investment.&#8221;</a></p></li><li><p><strong>The bill nobody quotes.</strong> Husain estimates <a href="https://hamel.dev/blog/posts/evals/">&#8220;99% of the labor involved with fine-tuning is assembling high-quality data.&#8221;</a> The <a href="https://arxiv.org/abs/2305.11206">LIMA result</a> cuts both ways: 1,000 curated examples fine-tuned a 65B model to outputs preferred over GPT-4&#8217;s in 43% of comparisons. Quality beats volume, and curating 1,000 excellent examples is still real work.</p></li></ul><p>Prompt caching is the middle path in production. Anthropic prices cache reads at <a href="https://docs.anthropic.com/en/docs/about-claude/pricing">0.1&#215; base input</a> and AWS says caching <a href="https://docs.aws.amazon.com/decision-guides/latest/decision-guides/bedrock-or-sagemaker.html">can cut costs up to 90%</a>. At GrowthX our source material changes weekly, so we&#8217;ve stayed on prompting plus RAG. I haven&#8217;t hit a case where a fine-tune was worth the data-assembly cost, which is a statement about our volatility rather than about fine-tuning.</p><h2>Security: assume the prompt leaks and the tools lie</h2><p>The documented record includes 15+ named injection incidents between 2022 and 2026, and in 2026 alone five CVE identifiers across four agent-framework incident groups. Google measured a <a href="https://blog.google/security/prompt-injections-web/">32% relative increase in malicious prompt-injection categories</a> on the web between November 2025 and February 2026.</p><p><strong>Injection.</strong> Riley Goodside demonstrated it <a href="https://threadreaderapp.com/thread/1569128808308957185.html">publicly</a> against GPT-3 in September 2022. By 2025 it was zero-click: <a href="https://nvd.nist.gov/vuln/detail/cve-2025-32711">EchoLeak (CVE-2025-32711)</a> exfiltrated data from Microsoft 365 Copilot with no user interaction. Researchers reported successful injections in <a href="https://arxiv.org/abs/2410.23308v1">56% of 144 tests across 36 models</a>. Wording will not save you; the mitigations are architectural. <a href="https://platform.claude.com/docs/en/docs/test-and-evaluate/strengthen-guardrails/mitigate-jailbreaks">Anthropic&#8217;s guardrail guidance</a> says to deliver third-party content inside <code>tool_result</code> blocks, keep it out of system prompts, and JSON-encode it so delimiters are unambiguous. OpenAI&#8217;s <a href="https://openai.com/index/designing-agents-to-resist-prompt-injection/">agent guidance</a> adds that defense &#8220;cannot rely only on filtering inputs. It also requires designing the system so that the impact of manipulation is constrained.&#8221; Least privilege per tool, confirmation before irreversible actions.</p><p><strong>Leaking.</strong> Kevin Liu pulled Bing Chat&#8217;s <a href="https://arstechnica.com/information-technology/2023/02/ai-powered-bing-chat-spills-its-secrets-via-prompt-injection-attack/">&#8220;Sydney&#8221; instructions</a> in February 2023. OWASP&#8217;s guidance is that <a href="https://genai.owasp.org/llmrisk/llm07-insecure-plugin-design/">&#8220;the system prompt should not be considered a secret, nor should it be used as a security control.&#8221;</a> Keep credentials and keys out of the prompt; assume it leaks.</p><p><strong>Jailbreaking.</strong> From DAN to <a href="https://arxiv.org/abs/2412.03556">Best-of-N attacks</a> at 89% success on GPT-4o with 10,000 augmented prompts. Layered classifiers are the answer that measures: Anthropic&#8217;s <a href="https://www.anthropic.com/research/constitutional-classifiers">Constitutional Classifiers</a> cut jailbreak success from 86% to 4.4%. Google Cloud&#8217;s <a href="https://docs.cloud.google.com/model-armor/overview">Model Armor</a> screens prompts and responses, OpenAI&#8217;s free <a href="https://platform.openai.com/docs/guides/moderation">Moderation API</a> covers the basics.</p><p>OpenAI calls adversarial robustness <a href="https://openai.com/index/prompt-injections/">&#8220;a hard, open problem,&#8221;</a> and Anthropic notes that even a 1% attack success rate &#8220;still represents meaningful risk.&#8221; Budget for defense in depth from day one if your agent reads email or the open web, both channels the <a href="https://arxiv.org/abs/2508.12175">Gemini promptware research</a> weaponized.</p><h2>Where prompts usually break</h2><ul><li><p><strong>Negative framing.</strong> &#8220;Be concise&#8221; is not testable. Anthropic recommends the positive form: instead of <code>"Do not use markdown"</code>, write <code>"Your response should be composed of smoothly flowing prose paragraphs."</code></p></li><li><p><strong>No output schema.</strong> It breaks parsers, and per OpenAI&#8217;s safety docs structured outputs also <a href="https://developers.openai.com/api/docs/guides/agent-builder-safety">&#8220;eliminate freeform channels that attackers can exploit.&#8221;</a> One constraint, two problems.</p></li><li><p><strong>Trusting the documented context window.</strong> Performance degrades <a href="https://aclanthology.org/2025.findings-emnlp.1264/">13.9%-85% within claimed windows</a>, with relevant information missed in <a href="https://aclanthology.org/2024.tacl-1.9/">middle positions</a>. We hit it ourselves: a vendor documented 128,000 tokens and our task started degrading well before that. Retrieve less, better.</p></li><li><p><strong>Technique for technique&#8217;s sake.</strong> CoT cost o1-preview 36.3 points on implicit-learning tasks, and in a <a href="https://arxiv.org/abs/2603.25960v1">2026 medical study</a> it cut accuracy 5.7% while few-shot examples cut it 11.9%.</p></li><li><p><strong>Not reading what your framework sends.</strong> Husain&#8217;s <a href="https://hamel.dev/blog/posts/prompt/">prompt inspection</a> found LangChain&#8217;s SmartLLMChain shipping a typo (<code>'Let'w'</code>) in its critique prompt and Guidance making 7 API calls where 2 sufficed. Log the raw request once per integration, minimum.</p></li></ul><h2>Evals are the job</h2><p>Draft, run against a fixed test set, score, change one variable, version like code. The loop exists because output varies: even temperature 0 isn&#8217;t deterministic, so one passing run proves nothing.</p><p>This is the reasoning behind Evals Driven Development: repeated runs scored against a rubric instead of exact-match assertions. After we rewrote the rubric, the measured pass rate on our 60-query test set went from 74% to 86%. That number is ours; the method transfers. Shreya Shankar&#8217;s guidance to <a href="https://hamel.dev/blog/posts/evals-faq/why-is-error-analysis-so-important-in-llm-evals-and-how-is-it-different-from-error-analysis-in-llm-evals-and-how-is-it-performed.html">review at least 100 traces before designing any rubric</a> matches our experience: rubrics written before error analysis test failures that never happen.</p><p>The checklist:</p><ol><li><p>Collect 50-100 real inputs before writing the prompt. Include the ugly ones.</p></li><li><p>Simplest zero-shot prompt with an explicit output format, run 3-5 times per input.</p></li><li><p>Error analysis first, rubric second, written from observed failures.</p></li><li><p>One variable at a time: wording, examples, format, technique.</p></li><li><p>Version every prompt, log every run. <a href="https://docs.promptlayer.com/features/prompt-registry/overview">PromptLayer&#8217;s registry</a> documents version diffs and release labels; LangSmith and Langfuse do the same job. Ours lives in Output, where prompts and evals sit next to traces and cost tracking in the repo. Disclosure: Output is my open-source project.</p></li><li><p>Gate merges on eval regressions. <a href="https://deepeval.com/docs/evaluation-unit-testing-in-ci-cd">DeepEval</a> runs in pytest with an <code>--official</code> baseline; the pattern generalizes.</p></li><li><p>Track tokens and cost per prompt version next to quality. A quality win that doubles spend is a decision, not a detail.</p></li></ol><p>Calibrate LLM judges against human labels before trusting them, and score asynchronously where you can. Synchronous judging adds seconds per request.</p><h2>FAQ</h2><p><strong>How do I pick a technique?</strong> Zero-shot with an output format. Few-shot when the pattern resists description. CoT for math and symbolic work on non-reasoning models, native thinking controls on reasoning models. Self-consistency or ToT only for batch work where an eval shows a gap worth 5-100&#215; the tokens. RAG when the knowledge is external, changes often, or is cheaper to retrieve than to stuff.</p><p><strong>How many examples should I use?</strong> Anthropic says 3-5 and is the only vendor publishing a number. The rule that matters more: measure zero-shot and 2-5 shots before you commit, because one example often scores below none.</p><p><strong>What temperature should I use?</strong> 0-0.3 for extraction and function calling, 0.7-1.0 for creative work, one of temperature or top_p but not both. On reasoning models, leave it alone and use <code>reasoning_effort</code>, <code>effort</code>, or <code>thinkingLevel</code>.</p><p><strong>Should I tell the model it&#8217;s an expert?</strong> For tone and scope, yes, one sentence. For accuracy, no. No vendor has published a controlled ablation showing it works on a current reasoning model, and irrelevant persona detail has measured costs.</p><p><strong>When does fine-tuning beat prompting?</strong> When prompting has a measured ceiling, the target is a stable style or format, and you have 50-100+ curated examples plus appetite for the data work. Below that, caching and RAG are cheaper.</p><p><strong>Should I use an automatic prompt optimizer?</strong> Only if you already have an eval suite, a few hundred representative examples, and a held-out test set. With those, GEPA is the strongest thing available. Without them, half the runs come out worse than zero-shot.</p><p><strong>Minimum security posture for a prompted feature?</strong> Assume the system prompt leaks, so keep secrets out of it. JSON-encode untrusted input and keep it out of developer messages. Least privilege per tool, a classifier on inputs, confirmation before irreversible actions.</p><p><strong>Is prompt engineering a viable career in 2026?</strong> No, and it never was. It was a job title minted by a hype cycle. The <a href="https://arxiv.org/html/2506.00058v2">University of Oulu study</a> found 72 exact-title postings out of 20,662, under 0.5%.</p><p>The skill went the other way. Lightcast counted mentions rising from ~1,400 in 2023 to ~6,300 in 2024, and O&#8217;Reilly measured <a href="https://www.oreilly.com/radar/technology-trends-for-2025/">456% year-over-year growth</a> in prompt engineering content usage. It became part of the job, like knowing how to write a migration.</p><p>&#8220;Loop engineering&#8221; is the 2026 reprise of the same bs. Real skill, fake title. Learn it as part of the stack.</p><p>The 2024 version of this post aged in two years. This one will too, and the part that ages first is always the benchmark numbers rather than the method. If you run these against your own eval set and get different numbers, I want to hear about it. Mine are one team&#8217;s.</p>]]></content:encoded></item><item><title><![CDATA[Joining GrowthX]]></title><description><![CDATA[We hiring founding engineers]]></description><link>https://journal.daniellopes.dev/p/joining-growthx</link><guid isPermaLink="false">https://journal.daniellopes.dev/p/joining-growthx</guid><dc:creator><![CDATA[Daniel Lopes]]></dc:creator><pubDate>Thu, 19 Dec 2024 16:46:57 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa71ca141-3e0d-47cd-a2fc-78d89c581555_1203x518.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I'm thrilled to share some exciting news: I've joined GrowthX.ai.</p><p>What we&#8217;ve achieved in just ~7 months since inception is remarkable. $3M+ in ARR. Profitable. Grew team to 15. Zero funding!</p><p>Here&#8217;s the backstory:</p><p>At the beginning of the year, I took a sabbatical to immerse myself in the world of large language models (LLMs). I dove deep into retrieval-augmented generation (RAG), prompting strategies, fine-tuning techniques, and more. </p><p>Fast forward to mid-September, I got introduced to <a href="https://www.linkedin.com/in/marcelsantilli/">Marcel Santilli</a>. Within minutes, it was clear&#8212;he was onto something big and had the experience + ambition to deliver on it.<br><br>Marcel's pitch:</p><ul><li><p>Brands need to become publishers.</p></li><li><p>Founders need to become influencers.</p></li><li><p>You need strategy + experts to deliver it, but AI can make it scalable.</p></li></ul><p>Having previously helped with marketing before, I immediately got it&#8212;and Marcel had already proven the model&#8217;s effectiveness. The technical and product needs for the business were exactly the kinds of things I had spent the last year+ studying.</p><p>In the past four months, we&#8217;ve spent long hours validating a roadmap, getting the right team structure, and defining the GTM. Now we have the ambitious goal of reaching $15 million in ARR by 2025. To achieve this, my top priorities are building the right infra and putting together a great technical team.</p><p>We just opened two roles for founding engineers: <a href="https://growthx.ai/careers">https://growthx.ai/careers</a>. We are a remote-first company hiring from anywhere, as long as we can have a 4-hour timezone overlap with San Francisco. If you&#8217;re interested, don&#8217;t hesitate to reach out!</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!FupV!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa71ca141-3e0d-47cd-a2fc-78d89c581555_1203x518.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!FupV!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa71ca141-3e0d-47cd-a2fc-78d89c581555_1203x518.png 424w, https://substackcdn.com/image/fetch/$s_!FupV!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa71ca141-3e0d-47cd-a2fc-78d89c581555_1203x518.png 848w, https://substackcdn.com/image/fetch/$s_!FupV!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa71ca141-3e0d-47cd-a2fc-78d89c581555_1203x518.png 1272w, https://substackcdn.com/image/fetch/$s_!FupV!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa71ca141-3e0d-47cd-a2fc-78d89c581555_1203x518.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!FupV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa71ca141-3e0d-47cd-a2fc-78d89c581555_1203x518.png" width="1203" height="518" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a71ca141-3e0d-47cd-a2fc-78d89c581555_1203x518.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:518,&quot;width&quot;:1203,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:25944,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!FupV!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa71ca141-3e0d-47cd-a2fc-78d89c581555_1203x518.png 424w, https://substackcdn.com/image/fetch/$s_!FupV!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa71ca141-3e0d-47cd-a2fc-78d89c581555_1203x518.png 848w, https://substackcdn.com/image/fetch/$s_!FupV!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa71ca141-3e0d-47cd-a2fc-78d89c581555_1203x518.png 1272w, https://substackcdn.com/image/fetch/$s_!FupV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa71ca141-3e0d-47cd-a2fc-78d89c581555_1203x518.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p>]]></content:encoded></item><item><title><![CDATA[7-Powers book notes]]></title><description><![CDATA[While mentoring the current Techstars cohort that I&#8217;m working with, I see myself mentioning Hamilton Helmer's book over and over.]]></description><link>https://journal.daniellopes.dev/p/7-powers-book-summary</link><guid isPermaLink="false">https://journal.daniellopes.dev/p/7-powers-book-summary</guid><dc:creator><![CDATA[Daniel Lopes]]></dc:creator><pubDate>Thu, 19 Sep 2024 02:32:18 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!e3KM!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fccabf69a-e56a-4912-9577-cd40cb789a6b_684x529.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>While mentoring the current Techstars cohort that I&#8217;m working with, I see myself mentioning <a href="https://www.amazon.com/7-Powers-Foundations-Business-Strategy/dp/0998116319">Hamilton Helmer's book</a> over and over. So here&#8217;s a quick a summary:</p><h1>Summary</h1><p>The main idea is that every single company that doesn't rely on cheating (corruption, government ties, etc.) to come to life and achieve long-term success (measured in profit/revenue) has to have at least one or more of these "powers":</p><ol><li><p>Scale Economies</p></li><li><p>Network effect</p></li><li><p>Counter positioning</p></li><li><p>Branding</p></li><li><p>Switching costs</p></li><li><p>Cornered resources</p></li><li><p>Process</p></li></ol><h2>Power progression</h2><p>The idea is that these powers aren't constant either, and especially in tech, things are much more dynamic than static. Just because you succeed with one of these powers doesn't mean it will sustain forever, and each power has different defensibility in the face of competition as well. He qualifies the impact and the moment you can rely on and try to chase each power based on the phases of the business:</p><ol><li><p>Origination</p></li><li><p>Take-off phase</p></li><li><p>Stability phase</p></li></ol><p>Each phase is self-explanatory, but his idea is that chasing specific barriers in the right phase of the business will build much higher competitive advantage and barriers for new players. Also, he is explicitly focused on business phases, not product life-cycle.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!e3KM!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fccabf69a-e56a-4912-9577-cd40cb789a6b_684x529.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!e3KM!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fccabf69a-e56a-4912-9577-cd40cb789a6b_684x529.jpeg 424w, https://substackcdn.com/image/fetch/$s_!e3KM!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fccabf69a-e56a-4912-9577-cd40cb789a6b_684x529.jpeg 848w, https://substackcdn.com/image/fetch/$s_!e3KM!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fccabf69a-e56a-4912-9577-cd40cb789a6b_684x529.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!e3KM!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fccabf69a-e56a-4912-9577-cd40cb789a6b_684x529.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!e3KM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fccabf69a-e56a-4912-9577-cd40cb789a6b_684x529.jpeg" width="684" height="529" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ccabf69a-e56a-4912-9577-cd40cb789a6b_684x529.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:529,&quot;width&quot;:684,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!e3KM!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fccabf69a-e56a-4912-9577-cd40cb789a6b_684x529.jpeg 424w, https://substackcdn.com/image/fetch/$s_!e3KM!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fccabf69a-e56a-4912-9577-cd40cb789a6b_684x529.jpeg 848w, https://substackcdn.com/image/fetch/$s_!e3KM!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fccabf69a-e56a-4912-9577-cd40cb789a6b_684x529.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!e3KM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fccabf69a-e56a-4912-9577-cd40cb789a6b_684x529.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h3>Powers applicable to Origination Phase</h3><p>Phase where you are between the creation of the business, building everything and just launched and/or haven't achieved growth or market fit yet.</p><ul><li><p>Counter positioning</p></li><li><p>Cornered resources</p></li></ul><h3>Applicable to Take-off Phase</h3><p>Take-off phase is when the business starts to achieve fast growth.</p><ul><li><p>Scale economies</p></li><li><p>Switching Costs</p></li><li><p>Network effect</p></li></ul><h3>Applicable to Stability phase</h3><p>The break between take-off and stability is when unit growth falls below about 30%-40% year.</p><ul><li><p>Branding</p></li><li><p>Process power</p></li></ul><h2>Now to the description and examples of each power (in order of business phases):</h2><h3>Counter positioning (origination)</h3><p>Can be identified by:</p><ul><li><p>An upstart who developed a superior business model.</p></li><li><p>That business model's ability to successfully challenge well-entrenched incumbents.</p></li><li><p>Steady accumulation of customers, all while incumbent remains paralyzed and unable to respond.</p></li></ul><p><strong>Ex</strong>: The new business model is superior to the incumbent's model due to lower costs and/or the ability to charge higher prices.</p><h4>Barrier of entrance:</h4><p>Incumbent(s) will eventually ask: "Am I better off staying the course, or adopting the new model?" If the answer is "stay off", then the barrier is high. A newcomer adopts a new, superior business model which the incumbent does not mimic due to anticipated damage to their existing business.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ryf8!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F27ef931d-d247-4d9f-8155-27abaec765d3_684x463.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ryf8!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F27ef931d-d247-4d9f-8155-27abaec765d3_684x463.jpeg 424w, https://substackcdn.com/image/fetch/$s_!ryf8!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F27ef931d-d247-4d9f-8155-27abaec765d3_684x463.jpeg 848w, https://substackcdn.com/image/fetch/$s_!ryf8!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F27ef931d-d247-4d9f-8155-27abaec765d3_684x463.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!ryf8!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F27ef931d-d247-4d9f-8155-27abaec765d3_684x463.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ryf8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F27ef931d-d247-4d9f-8155-27abaec765d3_684x463.jpeg" width="684" height="463" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/27ef931d-d247-4d9f-8155-27abaec765d3_684x463.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:463,&quot;width&quot;:684,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!ryf8!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F27ef931d-d247-4d9f-8155-27abaec765d3_684x463.jpeg 424w, https://substackcdn.com/image/fetch/$s_!ryf8!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F27ef931d-d247-4d9f-8155-27abaec765d3_684x463.jpeg 848w, https://substackcdn.com/image/fetch/$s_!ryf8!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F27ef931d-d247-4d9f-8155-27abaec765d3_684x463.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!ryf8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F27ef931d-d247-4d9f-8155-27abaec765d3_684x463.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h4>Counter-Positioning versus Disruptive Technologies (Clayton Christensen)</h4><ul><li><p>Digital photography vs Kodak - this is a DT, but not CP.</p></li><li><p>In-N-Out vs. McDonald's - this is CP, but not DT</p></li><li><p>Netflix streaming vs. HBO via cable - this is both CP and DT</p></li></ul><p>The case for playing humble: Cognitive Bias can play a role in deterring the incumbent. But the challenger, by its posture, may be able to influence such a move. How to attempt this? In its ascendancy, the challenger should avoid the temptation of trumpeting its superiority, instead suppressing that urge and adopting a tone of respect toward the incumbent.</p><p>Counter positioning is not exclusive. Different from other powers like Network Effect, strong counter positioning doesn't require (or create) a winner-takes-all situation.</p><h4>Five stages of the incumbent when dealing with successful counter positioning from a new challenger:</h4><ol><li><p>Denial (aka, "we are not competitors")</p></li><li><p>Ridicule (aka, "we are better")</p></li><li><p>Fear</p></li><li><p>Anger</p></li><li><p>Capitulation (frequently too late)</p></li></ol><p>Blockbuster execs showed all 5 stages in their public statements when facing Netflix. I personally dealt with founders on 1 and 2 many times (and always end up on 5 later).</p><p>Once market erosion becomes severe, a Counter-Positioned incumbent comes under tremendous pressure to do something; at the same time, they face great pressure to not upset the apple cart of the legacy business model. A frequent outcome of this duality? Let's call it dabbling: the incumbent puts a toe in the water, somehow, but refuses to commit in a way that meaningfully answers the challenge.</p><p>CP often underlies situations in which the following happens at the same time:</p><p>For the challenger:</p><ul><li><p>Rapid share gains</p></li><li><p>Strong profitability (or promise of it)</p></li></ul><p>For the incumbent:</p><ul><li><p>Share loss</p></li><li><p>Inability to counter the entrant's moves</p></li><li><p>Eventually management shake-up(s)</p></li><li><p>Capitulation</p></li></ul><div><hr></div><h3>Cornered resources (origination)</h3><p><strong>Benefit</strong>:</p><p>Cornered Resource can emerge in varied forms, offering uniquely different benefits. It might, for example, be preferential access to a valuable patent, such as that for a blockbuster drug; a required input, such as a cement producer's ownership of a nearby limestone source, or a cost-saving production manufacturing approach.</p><p><strong>Ex</strong>: In the Pixar case, the Brain Trust produced an uncommonly appealing product&#8212;"superior deliverables"&#8212;driving demand with very attractive price/volume combinations in the form of huge box office returns.</p><p><strong>Barrier</strong>:</p><p>Barrier in Cornered Resource is unlike anything we have encountered before. You might wonder: "Why does Pixar retain the Brain Trust?" Any one of this group would be highly sought after by other animated film companies, and yet over this period, and no doubt into the future, they have stayed with Pixar. In the case of spin casting technology, it is patent law, and in the case of cement inputs, it is property rights.</p><h4>The Five Tests to validate Cornered Resource:</h4><ol><li><p>Individual/Exclusive: If a firm repeatedly acquires coveted assets at attractive terms, then the proper strategy question is, "Why are they able to do this?" Ex: if Exxon was able to persistently gain the rights to desirable properties, then understanding their path to that is key. Do relative scale allows them to develop better discovery processes? If so, their discovery processes are the Cornered Resource.</p></li><li><p>Non-arbitraged: cost to keep the resource should be low enough to afford consistent differential returns (ex: a movie hiring Brad Pitt might move the box office but won't necessarily 10x the cost).</p></li><li><p>Transferable: If a resource creates value at a single company but would fail to do so at other companies, then isolating that resource as the source of Power would entail overlooking some other essential complement beyond operational excellence.</p></li><li><p>Ongoing: In searching for Power, a strategist tries to isolate a causal factor that explains continued differential returns. Ex. Post-it notes patent lasted for 30 years</p></li><li><p>Sufficient: The final Cornered Resource test concerns completeness: for a resource to qualify as Power, it must be sufficient for continued differential returns, assuming operational excellence. Ex. George Fisher joining Kodak wasn't enough.</p></li></ol><div><hr></div><h3>Switching costs (take-off phase)</h3><p><strong>Ex</strong>: SAP - 43% of users are unhappy but 85% say they will continue to pay for the product, and the sales validate their statements.</p><p><strong>Benefit</strong>:</p><p>A company that has embedded Switching Costs for its current customers can charge higher prices than competitors for equivalent products or services. Benefit only possible when you have additional offerings to sell.</p><p><strong>Barrier</strong>:</p><p>To offer an equivalent product, competitors must compensate customers for Switching Costs. The firm that has previously roped in the customer, then, can set or adjust prices in a way that puts their potential rival at a cost disadvantage, rendering such a challenge distinctly unattractive.</p><h4>Types of switching costs:</h4><ul><li><p>Financial: $ cost of investing and purchasing new solutions (ex: SAP)</p></li><li><p>Procedural: loss of familiarity or risk of adoption of a new product (ex: "nobody was ever fired for choosing IBM")</p></li><li><p>Relational: Affection with the provider (ex: sales team) or product/identity as a user.</p></li></ul><div><hr></div><h3>Network Effect (take-off phase)</h3><p><strong>Benefit</strong>:</p><p>Network Economies occur when the value of a product to a customer is increased by the use of the product by others (Branch Out vs LinkedIn)</p><p>A company in a leadership position with Network Economies can charge higher prices than its competitors, because of the higher value as a result of more users.</p><p><strong>Barrier</strong>:</p><p>For Network Economies, the barrier is the unattractive cost/benefit of gaining share, and this can be extremely high. In particular, the value deficit of a follower can be so large that the price discount needed to offset this is unthinkable.</p><p><strong>Example</strong>: The value of LinkedIn's HR Solutions Suite comes from the numbers of LinkedIn users, so LinkedIn can charge more than a competing product with fewer participants.</p><h4>Characteristics:</h4><p>Industries exhibiting Network Economies often exhibit these attributes:</p><ol><li><p>Winner take all: Businesses with strong Network Economies are frequently characterized by a tipping point: once a single firm achieves a certain degree of leadership, then the other firms just throw in the towel. Game over&#8212;the P&amp;L of a challenge would just be too ugly. For example, even a company as competent and with as deep pockets as Google could not unseat Facebook with Google+.</p></li><li><p>Boundedness: As powerful as this Barrier is, it is bounded by the character of the network, something well-demonstrated by the continued success of both Facebook and LinkedIn. Facebook has powerful Network Economies itself but these have to do with personal not professional interactions. The boundaries of the network effects determine the boundaries of the business.</p></li><li><p>Decisive early product: Due to tipping point dynamics, early relative scaling is critical in developing Power. Who scales the fastest is often determined by who gets the product most right early on. Facebook's trumping of MySpace is a good example.</p></li></ol><div><hr></div><h3>Scale Economies (take-off)</h3><p>The quality of declining unit costs with increased business size is referred to as Scale Economies.</p><p><strong>Benefit</strong>:</p><p>Some condition which yields material improvement in the cash flow of the Power wielder via reduced cost, enhanced pricing and/or decreased investment requirements.</p><p><strong>Barrier</strong>:</p><p>Some obstacle which engenders in competitors an inability and/or unwillingness to engage in behaviors that might, over time, arbitrage out this benefit.</p><p>For Scale Economies, the Benefit is straightforward: lowered costs. In the case of Netflix, their lead in subscribers translated directly into lower content costs per subscriber for originals and exclusives.</p><p><strong>Example</strong>:</p><p>Netflix paid $100M for House of Cards and their streaming business had 30M customers, then the cost per customer was three dollars and change. In this scenario, a competitor with only one million subscribers would have to ante up $100 per subscriber.</p><p>This situation creates a very difficult position for Netflix's smaller-scale streaming competitors. If they offer the same deliverable as Netflix, similar amounts of content for the same price, their P&amp;L will suffer. If they try to remediate this by offering less content or raising prices, customers will abandon their service and they will lose market share. Such a competitive cul-de-sac is the hallmark of Power.</p><div><hr></div><h3>Branding (stability phase)</h3><p>Branding as power to charge higher prices and sustain market share.</p><p><strong>Ex</strong>: Purchased a Diamond ring at Tiffany for $16,600 and one of similar size and cut at Costco for $6,600, then asked a reputable gemologist and appraiser to assess the rings' values: Costco ring at $8,000 plus setting costs, more than $2,000 above the selling price. Assessed Tiffany ring at $10,500 plus setting costs at a non-brand-name retailer.</p><p>"You got exactly what they said you were getting. Anything that is brand-name and has developed a reputation that Tiffany has developed, they've earned it over the years for quality control. You can go there [and] you don't have to think twice about your purchase. And you pay for that."</p><p><strong>Benefit</strong>:</p><p>A business with Branding power is able to charge a higher price for its offering due to one or both of these two reasons:</p><ol><li><p>Affective valence - The built-up associations with the brand elicit good feelings about the offering, distinct from the objective value of the good. (Ex Tiffany's)</p></li><li><p>Uncertainty reduction - A customer attains "peace of mind" knowing that the branded product will be just as expected. Consider another example: Bayer aspirin. Search for aspirin on Amazon.com and you will see a 200 count of Bayer 325 mg. aspirin for $9.47 side-by-side with a 500 count of Kirkland 325 mg. aspirin for $10.93. So Bayer has a price per tablet premium of 117%. Some customers still would prefer the Bayer because of diminished uncertainty: Bayer's long history of consistency makes customers more confident that they are getting exactly what they want.</p></li></ol><p>Note that the Benefit from Branding does not depend on prior ownership, as with Switching Costs.</p><p><strong>Barrier</strong>:</p><p>A strong brand can only be created over a lengthy period of reinforcing actions (hysteresis), which itself serves as the key Barrier.</p><div><hr></div><h3>Process (stability phase)</h3><p><strong>Ex</strong>. Toyota Process (TPS)</p><p><strong>Benefit</strong>:</p><p>A company with Process Power is able to improve product attributes and/or lower costs as a result of process improvements embedded within the organization. For example, Toyota has maintained the quality increases and cost reductions of the TPS over a span of decades; these assets do not disappear as new workers are brought in and older workers retire.</p><p><strong>Barrier</strong>:</p><p>These process advances are difficult to replicate, and can only be achieved over a long time period of sustained evolutionary advance. This inherent speed limit in achieving the Benefit results from two factors:</p><ol><li><p>Complexity - Returning to our example: automobile production, combined with all the logistic chains which support it, entails enormous complexity. If process improvements touch many parts of these chains, as they did with Toyota, then achieving them quickly will prove challenging, if not impossible.</p></li><li><p>Opacity - The development of TPS should tip us off to the long time constant inevitably faced by would-be imitators. The system was fashioned from the bottom up, over decades of trial and error. The fundamental tenets were never formally codified, and much of the organizational knowledge remained tacit, rather than explicit. It would not be an exaggeration to say that even Toyota did not have a full, top-down understanding of what they had created &#8212;it took fully fifteen years, for instance, before they were able to transfer TPS to their suppliers. GM's experience with NUMMI also implies the tacit character of this knowledge: even when Toyota wanted to illuminate their work processes, they could not entirely do so.</p></li></ol><div><hr></div><h3>Innovation is the key to achieving any of the powers</h3><p>Innovation is achieved by creating compelling value. There are three distinct paths to creating compelling value.</p><ol><li><p><strong>Capabilities-Led Compelling Value</strong>: Adobe Acrobat. Here the key capability brought to bear was Adobe's existing fluency at the intersection of software and graphics.</p></li><li><p><strong>Customer-Led Compelling Value</strong>: Corning Fiber Optics. Interaction at a distance. The uncertainty in this case is technical: "Can we invent it?"</p></li><li><p><strong>Competitor-Led Compelling Value</strong>: the Sony PlayStation. Sony perceived the value in immersion of 3D graphics and the gap in the competitors' offerings (Sega/Nintendo) to double down on 3D and launch PS1.</p></li></ol>]]></content:encoded></item><item><title><![CDATA[Resuming after 1 month break]]></title><description><![CDATA[Month-long break, Aimap.today & Techstars San Francisco]]></description><link>https://journal.daniellopes.dev/p/resuming-after-1-month-break</link><guid isPermaLink="false">https://journal.daniellopes.dev/p/resuming-after-1-month-break</guid><dc:creator><![CDATA[Daniel Lopes]]></dc:creator><pubDate>Fri, 13 Sep 2024 04:22:09 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/4e32954c-180b-410a-b3f9-c9c40c8007d3_1376x768.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I've been absent lately, as some of you noticed. I'd set aside three months for a focused "studying" period, and it was a lot of fun to dive deep into prompt engineering, evals, LLM product lifecycles, agents, and more. However, transitioning from my previous full-time job to 8+ hour study days was challenging. Because I'm usually not great at taking breaks (I think I never took more than 2 weeks off), this time I was determined to stick to my three-month deadline and disconnect. I hit the deadline and went completely offline. I had a blast spending a month road cycling in Spain &amp; Germany and a lot of time with family.</p><p>Now, I'm recharged and excited to be back! </p><p>Here are some learnings, a new project I shipped this week, and some plans for the next few months:</p><h2>Aimap.today: An Experiment with Agents &amp; Flows</h2><p>I recently focused on learning about agent tooling to build an AI company researcher for personal use.</p><p>The plan: Create an agent to find funding news, identify AI-related companies, analyze their websites, build a knowledge base, write a long form article about it, and categorize them into three tiers (foundational AI tech, AI-enabled, and AI users).</p><p>I explored several agent frameworks: <a href="https://www.crewai.com/">CrewAI</a>, <a href="https://langchain-ai.github.io/langgraph/">LangGraph</a> (LangChain&#8217;s agent take), <a href="https://www.llamaindex.ai/blog/introducing-llama-deploy-a-microservice-based-way-to-deploy-llamaindex-workflows">LlamaIndex's Llama-Agents</a> (a microservice take on agents, where each agent is it&#8217;s own service), and <a href="https://www.agentops.ai/">AgentOps</a> (very cool instrumentation tool). I also tried building flows with <a href="https://www.airops.com/">AirOps</a> and <a href="https://n8n.io/">n8n</a>. In the process of fetching and enriching the data I also tried <a href="https://jina.ai/reader/">Jina Reader/SERP</a>, <a href="https://you.com/">You.com</a> API, <a href="https://www.apollo.io/">Apollo</a> API, and <a href="https://www.clay.com/claygent">Clay agent</a>.</p><p>Ultimately, for now, I decided to take a stab at coding my own thing. Most existing frameworks focus on LLMs talking to each other, but all I needed was a workflow/pipeline to chain multiple processes together.</p><p>My current boilerplate is in Ruby, and I wasn't satisfied with the existing packages for API clients like Claude and OpenAI. So, I coded these from scratch as well. The whole project, including study time, took about two weeks. </p><p><strong>&#128073; The result is: <a href="https://aimap.today">https://aimap.today</a> . </strong>Please, check it out and let me know what you think.</p><p>I built this for myself and plan to add new companies weekly. There's more I want to do, including a weekly digest for newly researched companies. If you sign-up you&#8217;ll be notified when I finish the weekly digest part.</p><p>My next step is to explore more out-of-the-box platforms like AirOps and n8n, and try to covert my little workflow to these tools.</p><p>Code-wise the pipeline currently looks like this:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!AnT6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f563482-be06-42c0-bd11-270a130469d0_1200x1136.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!AnT6!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f563482-be06-42c0-bd11-270a130469d0_1200x1136.png 424w, https://substackcdn.com/image/fetch/$s_!AnT6!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f563482-be06-42c0-bd11-270a130469d0_1200x1136.png 848w, https://substackcdn.com/image/fetch/$s_!AnT6!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f563482-be06-42c0-bd11-270a130469d0_1200x1136.png 1272w, https://substackcdn.com/image/fetch/$s_!AnT6!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f563482-be06-42c0-bd11-270a130469d0_1200x1136.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!AnT6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f563482-be06-42c0-bd11-270a130469d0_1200x1136.png" width="1200" height="1136" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3f563482-be06-42c0-bd11-270a130469d0_1200x1136.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1136,&quot;width&quot;:1200,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:271666,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!AnT6!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f563482-be06-42c0-bd11-270a130469d0_1200x1136.png 424w, https://substackcdn.com/image/fetch/$s_!AnT6!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f563482-be06-42c0-bd11-270a130469d0_1200x1136.png 848w, https://substackcdn.com/image/fetch/$s_!AnT6!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f563482-be06-42c0-bd11-270a130469d0_1200x1136.png 1272w, https://substackcdn.com/image/fetch/$s_!AnT6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f563482-be06-42c0-bd11-270a130469d0_1200x1136.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>Joined Techstars for the First San Francisco class</h2><p>I'm thrilled to share that I&#8217;ll be helping Techstars&#8217; first San Francisco class as an EIR (Entrepreneur in Residence). I've been following my friend and former boss, <a href="https://www.linkedin.com/in/nealsalesgriffin/">Neal</a>, as he ran Techstars Chicago and Oakland. When he mentioned the new San Francisco class, I jumped at the chance to participate.</p><p>The cohort is impressive, featuring many interesting AI-enabled businesses. I'm excited to work with all the founders. You can view the full cohort here: <a href="https://www.techstars.com/newsroom/techstars-announces-inaugural-class-of-san-francisco-accelerator">https://www.techstars.com/newsroom/techstars-announces-inaugural-class-of-san-francisco-accelerator</a></p><div><hr></div><p>It's great to be back. Building aimap.today has been an a cool learning experience, and I'm eager to continue improving and expanding it. </p><p>Joining Techstars as an EIR is another exciting opportunity I'm looking forward to.</p><p>I also may be joining a team on a new project soon, but I'll save that for future updates.</p><p>Going forward, my goal is to resume weekly updates.</p>]]></content:encoded></item><item><title><![CDATA[LLM Impact Mapping: A 4-Step Thought Exercise with Claude 3.5]]></title><description><![CDATA[Using Langchain + Claude 3.5 to brainstorm about AI's effect on common roles]]></description><link>https://journal.daniellopes.dev/p/llm-impact-mapping-a-4-step-thought</link><guid isPermaLink="false">https://journal.daniellopes.dev/p/llm-impact-mapping-a-4-step-thought</guid><dc:creator><![CDATA[Daniel Lopes]]></dc:creator><pubDate>Wed, 10 Jul 2024 13:02:11 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/70779090-5701-49a0-ba1f-9d22c64fb57f_1376x768.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I'm starting to plan what to do next in the long run, and I&#8217;m entertaining the idea of joining a team. I think things might be moving too fast and too much demand for skills for risking time on solo projects.</p><h3>Three types of play</h3><p>Started considering which spaces are interesting now. I think this take from <a href="https://www.amazon.com/7-Powers-Foundations-Business-Strategy/dp/0998116319">Hamilton Helmer</a> is a good one: Three types of play:</p><ol><li><p>The tech play: example of semiconductors, you get Intel and etc.</p></li><li><p>The first-tier play: companies that wouldn't exist before semiconductors (Microsoft)</p></li><li><p>The usage play: car companies with tons of semiconductors. They already existed, just got better.</p></li></ol><p>The whole video is worth watching, but <a href="https://youtu.be/hKq1_KPSqy0?t=2367">heres&#8217; the time-stamp about AI.</a></p><p>I'm personally more interested in the second play. And finding these companies early and identifying which ones are already in a good direction is so hard.</p><h3>Brainstorm exercise</h3><p>A good place to start could be looking at common roles and how they will be impacted and can be augmented or even replaced. </p><p>A programmer's job is already seriously impacted, customer support even more so. Same for SDRs. Some other roles, like localization, have already been pretty much replaced. These highly impacted roles are the things I'm most interested in.</p><p>So, just as a thought exercise toying with Python + Langchain, I wrote a 4-step chain with Claude 3.5 to do following:</p><ol><li><p>Brainstorm departments and roles common across any vertical</p></li><li><p>List the most common tasks in those roles</p></li><li><p>Brainstorm ideas for how each could be augmented or automated</p></li><li><p>(Rank them by difficulty and confidence, but this was just for nudging the model)</p></li></ol><p>I only spent a couple of hours and $3 in credits, but the results turned out better than I was expecting. </p><p>There's obviously some nonsense and some things that are regular ML models more than LLMs in the output (my fault, I should have optimized the last step of the chain better), but a lot of solid ones that I think haven't happened yet, and some others in the &#8220;augmentation&#8221; category fully in progress like Figma, Intercom, Cursor, GitHub Copilot, etc. If you squint and look at the roles with the best ideas, you can see <a href="https://www.qualified.com/ai-sdr">Piper</a>, <a href="https://www.intercom.com/drlp/ai-chatbot">Fin</a>, <a href="https://www.harvey.ai/">Harvey</a>, <a href="https://www.wisq.com/">Wisq</a>, <a href="https://www.cognition.ai/blog/introducing-devin">Devin</a>, <a href="https://www.11x.ai/">11x.ai</a>, etc</p><h3>You can see the whole list here:</h3><p><a href="https://docs.google.com/spreadsheets/d/1vpXzfUFNhIZJp9CEmiZqGKaVrP_Xx8McMZZlLCxiHNg/edit?gid=0#gid=0">https://docs.google.com/spreadsheets/d/1vpXzfUFNhIZJp9CEmiZqGKaVrP_Xx8McMZZlLCxiHNg/edit?gid=0#gid=0</a></p><p>Next step, I guess, is to start collecting companies and maybe have a little agent help me with the research.</p><p>&#8212;</p><p>I haven't had time to think through the whole list yet, but here...Some of the ones that stood out that the ideas are mostly very doable, or already happening:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!XTZp!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa3d6389c-8d57-47e6-b30e-6b981d6c1c1d_1858x1086.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!XTZp!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa3d6389c-8d57-47e6-b30e-6b981d6c1c1d_1858x1086.png 424w, https://substackcdn.com/image/fetch/$s_!XTZp!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa3d6389c-8d57-47e6-b30e-6b981d6c1c1d_1858x1086.png 848w, https://substackcdn.com/image/fetch/$s_!XTZp!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa3d6389c-8d57-47e6-b30e-6b981d6c1c1d_1858x1086.png 1272w, https://substackcdn.com/image/fetch/$s_!XTZp!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa3d6389c-8d57-47e6-b30e-6b981d6c1c1d_1858x1086.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!XTZp!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa3d6389c-8d57-47e6-b30e-6b981d6c1c1d_1858x1086.png" width="1456" height="851" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a3d6389c-8d57-47e6-b30e-6b981d6c1c1d_1858x1086.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:851,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:187794,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!XTZp!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa3d6389c-8d57-47e6-b30e-6b981d6c1c1d_1858x1086.png 424w, https://substackcdn.com/image/fetch/$s_!XTZp!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa3d6389c-8d57-47e6-b30e-6b981d6c1c1d_1858x1086.png 848w, https://substackcdn.com/image/fetch/$s_!XTZp!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa3d6389c-8d57-47e6-b30e-6b981d6c1c1d_1858x1086.png 1272w, https://substackcdn.com/image/fetch/$s_!XTZp!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa3d6389c-8d57-47e6-b30e-6b981d6c1c1d_1858x1086.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!BlOh!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08d1abb9-6463-47a3-adda-95de741f35e2_1856x1078.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!BlOh!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08d1abb9-6463-47a3-adda-95de741f35e2_1856x1078.png 424w, https://substackcdn.com/image/fetch/$s_!BlOh!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08d1abb9-6463-47a3-adda-95de741f35e2_1856x1078.png 848w, https://substackcdn.com/image/fetch/$s_!BlOh!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08d1abb9-6463-47a3-adda-95de741f35e2_1856x1078.png 1272w, https://substackcdn.com/image/fetch/$s_!BlOh!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08d1abb9-6463-47a3-adda-95de741f35e2_1856x1078.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!BlOh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08d1abb9-6463-47a3-adda-95de741f35e2_1856x1078.png" width="1456" height="846" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/08d1abb9-6463-47a3-adda-95de741f35e2_1856x1078.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:846,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:207782,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!BlOh!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08d1abb9-6463-47a3-adda-95de741f35e2_1856x1078.png 424w, https://substackcdn.com/image/fetch/$s_!BlOh!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08d1abb9-6463-47a3-adda-95de741f35e2_1856x1078.png 848w, https://substackcdn.com/image/fetch/$s_!BlOh!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08d1abb9-6463-47a3-adda-95de741f35e2_1856x1078.png 1272w, https://substackcdn.com/image/fetch/$s_!BlOh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08d1abb9-6463-47a3-adda-95de741f35e2_1856x1078.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!DYQl!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c1d25e5-330e-49f3-a50d-c7771bd1eb30_1672x1132.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!DYQl!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c1d25e5-330e-49f3-a50d-c7771bd1eb30_1672x1132.png 424w, https://substackcdn.com/image/fetch/$s_!DYQl!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c1d25e5-330e-49f3-a50d-c7771bd1eb30_1672x1132.png 848w, https://substackcdn.com/image/fetch/$s_!DYQl!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c1d25e5-330e-49f3-a50d-c7771bd1eb30_1672x1132.png 1272w, https://substackcdn.com/image/fetch/$s_!DYQl!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c1d25e5-330e-49f3-a50d-c7771bd1eb30_1672x1132.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!DYQl!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c1d25e5-330e-49f3-a50d-c7771bd1eb30_1672x1132.png" width="1456" height="986" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0c1d25e5-330e-49f3-a50d-c7771bd1eb30_1672x1132.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:986,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:230704,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!DYQl!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c1d25e5-330e-49f3-a50d-c7771bd1eb30_1672x1132.png 424w, https://substackcdn.com/image/fetch/$s_!DYQl!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c1d25e5-330e-49f3-a50d-c7771bd1eb30_1672x1132.png 848w, https://substackcdn.com/image/fetch/$s_!DYQl!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c1d25e5-330e-49f3-a50d-c7771bd1eb30_1672x1132.png 1272w, https://substackcdn.com/image/fetch/$s_!DYQl!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c1d25e5-330e-49f3-a50d-c7771bd1eb30_1672x1132.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!D9Q-!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6899800e-3f2c-4dba-b440-013c5a15e85f_1670x712.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!D9Q-!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6899800e-3f2c-4dba-b440-013c5a15e85f_1670x712.png 424w, https://substackcdn.com/image/fetch/$s_!D9Q-!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6899800e-3f2c-4dba-b440-013c5a15e85f_1670x712.png 848w, https://substackcdn.com/image/fetch/$s_!D9Q-!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6899800e-3f2c-4dba-b440-013c5a15e85f_1670x712.png 1272w, https://substackcdn.com/image/fetch/$s_!D9Q-!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6899800e-3f2c-4dba-b440-013c5a15e85f_1670x712.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!D9Q-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6899800e-3f2c-4dba-b440-013c5a15e85f_1670x712.png" width="1456" height="621" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6899800e-3f2c-4dba-b440-013c5a15e85f_1670x712.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:621,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:124803,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!D9Q-!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6899800e-3f2c-4dba-b440-013c5a15e85f_1670x712.png 424w, https://substackcdn.com/image/fetch/$s_!D9Q-!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6899800e-3f2c-4dba-b440-013c5a15e85f_1670x712.png 848w, https://substackcdn.com/image/fetch/$s_!D9Q-!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6899800e-3f2c-4dba-b440-013c5a15e85f_1670x712.png 1272w, https://substackcdn.com/image/fetch/$s_!D9Q-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6899800e-3f2c-4dba-b440-013c5a15e85f_1670x712.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!dRf6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd07a9170-2afa-4b1d-8b8f-77506ab052a4_1670x1084.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!dRf6!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd07a9170-2afa-4b1d-8b8f-77506ab052a4_1670x1084.png 424w, https://substackcdn.com/image/fetch/$s_!dRf6!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd07a9170-2afa-4b1d-8b8f-77506ab052a4_1670x1084.png 848w, https://substackcdn.com/image/fetch/$s_!dRf6!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd07a9170-2afa-4b1d-8b8f-77506ab052a4_1670x1084.png 1272w, https://substackcdn.com/image/fetch/$s_!dRf6!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd07a9170-2afa-4b1d-8b8f-77506ab052a4_1670x1084.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!dRf6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd07a9170-2afa-4b1d-8b8f-77506ab052a4_1670x1084.png" width="1456" height="945" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d07a9170-2afa-4b1d-8b8f-77506ab052a4_1670x1084.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:945,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:206206,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!dRf6!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd07a9170-2afa-4b1d-8b8f-77506ab052a4_1670x1084.png 424w, https://substackcdn.com/image/fetch/$s_!dRf6!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd07a9170-2afa-4b1d-8b8f-77506ab052a4_1670x1084.png 848w, https://substackcdn.com/image/fetch/$s_!dRf6!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd07a9170-2afa-4b1d-8b8f-77506ab052a4_1670x1084.png 1272w, https://substackcdn.com/image/fetch/$s_!dRf6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd07a9170-2afa-4b1d-8b8f-77506ab052a4_1670x1084.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p>]]></content:encoded></item><item><title><![CDATA[Week 10: Mostly LLM Evaluations]]></title><description><![CDATA[Machine learning + Evaluations]]></description><link>https://journal.daniellopes.dev/p/week-10-mostly-llm-evaluations</link><guid isPermaLink="false">https://journal.daniellopes.dev/p/week-10-mostly-llm-evaluations</guid><dc:creator><![CDATA[Daniel Lopes]]></dc:creator><pubDate>Mon, 08 Jul 2024 22:24:14 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43931fc2-a950-4d4e-8662-44e8ded1f3a4_2144x1306.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The first week of July has already passed. If you're new here, two months ago, I left my full-time job to focus on exploring LLMs. While I've learned a lot in just two months, June wasn't as productive as I'd hoped, with too much time spent on non-AI coding projects, leaving me with time for just theory and conferences. I'm aiming to correct this in July.</p><h2>Traditional machine learning</h2><p>When you move beyond simply calling APIs, you'll encounter the traditional ML stack and terminology. For instance, if you need to adjust your embeddings and choose a different model, you'll need a solid grasp of metrics like BPB, BPC, Perplexity, and so on. The same goes for evaluating production data.</p><p>I also prefer not to have components in a stack that I don't understand at a high level, even if I don't have to work with them directly (for example, if I'm an EM on the product side or a product manager).</p><p>For ML theory I&#8217;m currently <a href="https://www.youtube.com/playlist?list=PLrQmbzbRJ5mwDinvDEJ5B-KDZlPM-sCYO">half way through this course</a>.  It may be a few years old, but I appreciate how practical and real-world focused it is. If anyone has other suggestions, I'm very open to them.</p><p>I can't recall the exact source of this slide (I think it was from <a href="https://x.com/HamelHusain?ref_src=twsrc%5Egoogle%7Ctwcamp%5Eserp%7Ctwgr%5Eauthor">Hamel Hussain&#8217;s talk</a> on AI Engineer conf this month) , but I believe it provides a reasonable overview - and my goal is to have at least a basic understanding of everything under the horizontal line.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!I8IB!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe270dc33-bd20-45fd-a9e8-47ba92e5bec0_1472x874.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!I8IB!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe270dc33-bd20-45fd-a9e8-47ba92e5bec0_1472x874.png 424w, https://substackcdn.com/image/fetch/$s_!I8IB!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe270dc33-bd20-45fd-a9e8-47ba92e5bec0_1472x874.png 848w, https://substackcdn.com/image/fetch/$s_!I8IB!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe270dc33-bd20-45fd-a9e8-47ba92e5bec0_1472x874.png 1272w, https://substackcdn.com/image/fetch/$s_!I8IB!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe270dc33-bd20-45fd-a9e8-47ba92e5bec0_1472x874.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!I8IB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe270dc33-bd20-45fd-a9e8-47ba92e5bec0_1472x874.png" width="1456" height="865" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e270dc33-bd20-45fd-a9e8-47ba92e5bec0_1472x874.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:865,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:842510,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!I8IB!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe270dc33-bd20-45fd-a9e8-47ba92e5bec0_1472x874.png 424w, https://substackcdn.com/image/fetch/$s_!I8IB!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe270dc33-bd20-45fd-a9e8-47ba92e5bec0_1472x874.png 848w, https://substackcdn.com/image/fetch/$s_!I8IB!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe270dc33-bd20-45fd-a9e8-47ba92e5bec0_1472x874.png 1272w, https://substackcdn.com/image/fetch/$s_!I8IB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe270dc33-bd20-45fd-a9e8-47ba92e5bec0_1472x874.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>Evaluations</h2><p>Last week, I began studying evaluations more seriously for two reasons. First, I'm working on understanding the various stages of the development cycle. Second, I need to establish a better workflow for iterating on our <a href="https://canopy.is/m/training/ai_assistant">AI bot at Canopy</a>.</p><p>For theory around evals I really liked <a href="https://x.com/chipro">Chip</a>&#8217;s <a href="https://learning.oreilly.com/library/view/ai-engineering/9781098166298/ch03.html#why_ai_as_a_judge">third chapter of her WIP book</a>. This <a href="https://hamel.dev/blog/posts/evals/">post about Evaluations from Hamel Husain</a> is also so good, and <a href="https://applied-llms.org/#evaluation-monitoring">this one as well</a>.</p><p><strong>This is would be the ideal cycle for me:</strong></p><p></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Or6c!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43931fc2-a950-4d4e-8662-44e8ded1f3a4_2144x1306.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Or6c!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43931fc2-a950-4d4e-8662-44e8ded1f3a4_2144x1306.png 424w, https://substackcdn.com/image/fetch/$s_!Or6c!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43931fc2-a950-4d4e-8662-44e8ded1f3a4_2144x1306.png 848w, https://substackcdn.com/image/fetch/$s_!Or6c!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43931fc2-a950-4d4e-8662-44e8ded1f3a4_2144x1306.png 1272w, https://substackcdn.com/image/fetch/$s_!Or6c!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43931fc2-a950-4d4e-8662-44e8ded1f3a4_2144x1306.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Or6c!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43931fc2-a950-4d4e-8662-44e8ded1f3a4_2144x1306.png" width="1456" height="887" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/43931fc2-a950-4d4e-8662-44e8ded1f3a4_2144x1306.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:887,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:144725,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Or6c!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43931fc2-a950-4d4e-8662-44e8ded1f3a4_2144x1306.png 424w, https://substackcdn.com/image/fetch/$s_!Or6c!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43931fc2-a950-4d4e-8662-44e8ded1f3a4_2144x1306.png 848w, https://substackcdn.com/image/fetch/$s_!Or6c!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43931fc2-a950-4d4e-8662-44e8ded1f3a4_2144x1306.png 1272w, https://substackcdn.com/image/fetch/$s_!Or6c!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43931fc2-a950-4d4e-8662-44e8ded1f3a4_2144x1306.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">This is sort of the workflow that I think it would be ideal for me.</figcaption></figure></div><p>At Canopy, our tech stack is entirely Ruby, and our AI Assistant was built using direct API calls to OpenAI. While I did implement some observability, I still need a more robust way to monitor the quality of answers in production and a solid test suite that I can run when updating the model or modifying the prompts.</p><p>Ideally, I would have automated tests similar to regular test units that I can run whenever I'm iterating on prompts, models, or content format for the rag. Once things are deployed, I'd like to have comparable quality metrics for the production data, with alerts if quality drops below certain thresholds and proper visibility.</p><p>There are quite a few LLM-focused evaluation tools available, and many of them are really solid. I don't mean to dismiss their work, but for my specific context, here's my current assessment:</p><ol><li><p>They do too much</p><ol><li><p>Most tools attempt to offer solutions for all four stages of my diagram, but these companies are often small, seed-level teams building in a rapidly evolving space. Many of these products feel either half-baked or are still trying to figure out their business model. I'd prefer a tool that focuses solely on the two evaluation parts (dev &amp; production) and doesn't try to handle the prototyping and deployment aspects.</p></li></ol></li><li><p>Their business models are still unclear</p><ol><li><p>Many tools are in the typical early-stage B2B mode, lacking a product-led path and aiming to lock users into annual contracts with case-by-case pricing. I understand this is important in a new market with early-stage products, but I'd love to see more product-led options (especially for Canopy's context, a small team where the bot isn't their core feature yet).</p></li></ol></li><li><p>Vendor lock in / dependency risk</p><ol><li><p>To enable tracing, many tools heavily wrap around API clients for services like OpenAI, and some don't even offer public API versions. Tools that offer "solutions" for the deployment part often proxy calls under their own API, so instead of calling OpenAI directly, you call their API. This introduces a third-party proxy as a potential failure point, in addition to OpenAI/Anthropic/etc., and it's built by an understaffed seed company. </p></li></ol></li><li><p>Pretty much no solutions for non-Python/JavaScript stacks</p><ol><li><p>Most niceties for automatic logging/tracing and basic metrics like latency come from their SDK, which are often limited to Python/JS. While understandable given the early stage, most tools also don't offer a public API. For more elaborate setups, a reasonable workflow could be to follow the traditional ML path of using Python for the stack and wrapping it as an API for other languages to call, instead of relying on a proxy maintained by a tiny company in a crowded space. It's a bit of a bummer because for AI products that only need LLMs, it's an overcomplication in the stack. You'll definitely need query augmentation, retries, rate-limiting controls, and other things a product-level software already handles, and now you'll need to duplicate that in the Python stack too. It's one thing when you're making an API around a model you control, but it's another when you're making an API around another API.</p></li></ol></li></ol><p>If you're already using a Python or JS stack, you have fewer things to worry about. However, for Canopy (Ruby stack), the situation is a bit different. I think I'll go with the following approach:</p><ul><li><p><strong>First:</strong> Find a tool that has a public API support for sending run data for production, build a small Ruby client for that, and do production level monitoring only (similar to how&#8217;d use a service like Sentry).  Ignore all the other 3 stages of  the Experiment and Deploy part of these tools.</p><ul><li><p><strong>Second:</strong> </p><ul><li><p>Have a good unit test coverage for the direct calls to OpenAI with VCR and reimplement some of the basic eval metrics that relevant to my context like <strong>Answer Relevance, Context Recall, or Context Relevancy. </strong></p></li><li><p>Or use something like <a href="https://www.promptfoo.dev/">Promptfoo</a>, <a href="https://ragas.io/">Ragas</a> or <a href="https://www.guardrailsai.com/">GuardRails</a> for the local unit tests.</p></li></ul></li></ul><p></p></li></ul><p>I haven't decided which product to use yet, but reading through their documentation, examining the code of their SDKs, and exploring their offerings has been a good learning process already.</p><p>In no particular order, here's the current list of evaluation products/projects that I'm aware of (although I haven't had a chance to thoroughly check all of them yet):</p><ul><li><p>https://mlflow.org</p></li><li><p>https://www.vellum.ai/</p></li><li><p>https://athina.ai</p></li><li><p>https://www.patronus.ai</p></li><li><p>https://wandb.ai/site/weave</p></li><li><p>https://autochain.forethought.ai/</p></li><li><p>https://ragas.io/</p></li><li><p>https://github.com/agenta-ai/agenta</p></li><li><p>https://klu.ai/</p></li><li><p>https://www.braintrustdata.com/</p></li><li><p>https://humanloop.com/</p></li><li><p>https://www.parea.ai/</p></li><li><p>https://docs.llamaindex.ai/en/stable/understanding/evaluating/evaluating/</p></li><li><p>https://www.langchain.com/langsmith</p></li><li><p>https://github.com/langfuse/langfuse</p></li><li><p>https://www.rungalileo.io/</p></li><li><p>https://www.guardrailsai.com/</p></li><li><p>https://deepchecks.com</p></li><li><p>https://arize.com</p></li><li><p>https://github.com/UKGovernmentBEIS/inspect_ai</p></li></ul><p>If you're using a tool that you really like or if you have any feedback or a different perspective on the market, I'd love to hear your thoughts.</p>]]></content:encoded></item><item><title><![CDATA[Month 2]]></title><description><![CDATA[Lots of papers, coffee chats, contract work, and conferences&#8230;]]></description><link>https://journal.daniellopes.dev/p/week-5-6-and-7</link><guid isPermaLink="false">https://journal.daniellopes.dev/p/week-5-6-and-7</guid><dc:creator><![CDATA[Daniel Lopes]]></dc:creator><pubDate>Thu, 27 Jun 2024 03:35:40 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/19c36a55-81bd-4455-afd5-88ccdf573992_1376x768.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I've been away for a couple of weeks, spent probably 30% of my time networking and meeting people, and the rest helping my friends at <a href="https://getkoala.com">Koala</a>. This meant missing two weekly posts and delaying the public release of <a href="https://replayjournal.ai">Replay</a>. The app is working well, but I&#8217;m having a tough time finding time for the last details and GTM.</p><p>While I haven't done much hands-on AI engineering this last two weeks, I've been keeping up with theory. Here's some of the notes:</p><h2>Daily Prompting Paper</h2><p>For a while now, I've been checking <a href="https://arxiv.org/search/?query=LLM+prompt&amp;searchtype=all&amp;source=header">Arxiv daily for new papers on Prompt Engineering</a>. It's a topic that's usually easy to understand, even in academic papers, so great way to kill time between tasks.</p><p>Many poor results in AI come from inadequate prompting skills + techniques like prompt chaining and retries, weren't practical before, but now make sense.</p><p>In June, <a href="https://arxiv.org/abs/2406.06608">this excellent paper</a> was published. I spent the last couple of weeks reading it thoroughly, along with many of its citations. I've <a href="https://journal.daniellopes.dev/p/practical-prompt-engineering-notes">compiled some notes here</a>, and I'm also planning to create a better structured resource with more examples and additional notes I didn't include.</p><h2>Meetups and Conferences</h2><p>I've been attending several meetups and conferences, including <a href="https://www.aiqualityconference.com">AIQCon</a> yesterday. It's interesting to see the growing focus on AI Engineering (meaning implementing GenAI in products). Last year, there a lot of interest in LLMs themselves, but now the emphasis is on making LLMs perform well in real-world applications.</p><p>Key topics include:</p><ul><li><p>RAG (Retrieval-Augmented Generation): Techniques to improving embeddings, content augmentation, and advanced techniques like GraphRAG.</p></li><li><p>Evaluation: Setting up good test suites, deciding what to test, and determining who should write the tests.</p></li><li><p>No fine-tuning: The consensus is to focus on prompting, RAG, and evaluation before considering fine-tuning. Lot of pain and scar from fine-tuning already.</p></li></ul><p>While some events feel like they have a high noise-to-signal ratio, I always learn a lot as a newcomer. Also, it&#8217;s such a great time to live in SF. For future conferences, I plan to research the participants and their topics more thoroughly beforehand.</p><p>A useful resource from yesterday's conference: <a href="https://huyenchip.com/llama-police.html">https://huyenchip.com/llama-police.html</a> by <a href="https://x.com/chipro">Chip Huyen</a> (well worth following on X).</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!O9hC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe49d4ae-5b73-4b6c-8c1b-77d9467ffa75_1396x1280.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!O9hC!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe49d4ae-5b73-4b6c-8c1b-77d9467ffa75_1396x1280.png 424w, https://substackcdn.com/image/fetch/$s_!O9hC!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe49d4ae-5b73-4b6c-8c1b-77d9467ffa75_1396x1280.png 848w, https://substackcdn.com/image/fetch/$s_!O9hC!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe49d4ae-5b73-4b6c-8c1b-77d9467ffa75_1396x1280.png 1272w, https://substackcdn.com/image/fetch/$s_!O9hC!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe49d4ae-5b73-4b6c-8c1b-77d9467ffa75_1396x1280.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!O9hC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe49d4ae-5b73-4b6c-8c1b-77d9467ffa75_1396x1280.png" width="1396" height="1280" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/be49d4ae-5b73-4b6c-8c1b-77d9467ffa75_1396x1280.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1280,&quot;width&quot;:1396,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2923913,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!O9hC!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe49d4ae-5b73-4b6c-8c1b-77d9467ffa75_1396x1280.png 424w, https://substackcdn.com/image/fetch/$s_!O9hC!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe49d4ae-5b73-4b6c-8c1b-77d9467ffa75_1396x1280.png 848w, https://substackcdn.com/image/fetch/$s_!O9hC!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe49d4ae-5b73-4b6c-8c1b-77d9467ffa75_1396x1280.png 1272w, https://substackcdn.com/image/fetch/$s_!O9hC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe49d4ae-5b73-4b6c-8c1b-77d9467ffa75_1396x1280.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>Books</h2><p>On the topic of learning more theory, I'm currently reading two books:</p><p>1. <strong>Programming Machine Learning</strong></p><p><a href="https://www.amazon.com/Programming-Machine-Learning-Zero-Deep/dp/1680506609">https://www.amazon.com/Programming-Machine-Learning-Zero-Deep/dp/1680506609</a></p><p>I first read this when it was released, but I've forgotten most of it. Although it's a bit outdated and pre-LLM, I like the author's writting. Given how close AI Engineering is to traditional ML, I want to revisit this material.</p><p><strong>2. Neural Nets mini-course by 3Blue1Brown</strong></p><p>Another basic entry level material I was revisiting this week is this mini-course on neural nets: <a href="https://www.youtube.com/playlist?list=PLZHQObOWTQDNU6R1_67000Dx_ZCJB-3pi">https://www.youtube.com/playlist?list=PLZHQObOWTQDNU6R1_67000Dx_ZCJB-3pi</a></p><p>2. <strong>Oreilly&#8217;s</strong> <strong>AI Engineering book</strong></p><p><a href="https://www.oreilly.com/library/view/ai-engineering/9781098166298/cover.html">https://www.oreilly.com/library/view/ai-engineering/9781098166298/cover.html</a></p><p>This book was recommended by a close person, and I attended a talk by the author yesterday - it was one of my favorites, despite being too short. Only three chapters are available now, so I'll keep an eye out for future updates.</p>]]></content:encoded></item><item><title><![CDATA[W3 Recap: 4o, Marketing & Product work]]></title><description><![CDATA[3 days off but still managed to make some progress&#8230;]]></description><link>https://journal.daniellopes.dev/p/w3-recap-4o-marketing-and-product</link><guid isPermaLink="false">https://journal.daniellopes.dev/p/w3-recap-4o-marketing-and-product</guid><dc:creator><![CDATA[Daniel Lopes]]></dc:creator><pubDate>Tue, 28 May 2024 03:45:17 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!BYVN!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18b54220-d42f-4f1e-b01e-1321de9d486c_1376x768.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!BYVN!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18b54220-d42f-4f1e-b01e-1321de9d486c_1376x768.webp" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!BYVN!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18b54220-d42f-4f1e-b01e-1321de9d486c_1376x768.webp 424w, https://substackcdn.com/image/fetch/$s_!BYVN!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18b54220-d42f-4f1e-b01e-1321de9d486c_1376x768.webp 848w, https://substackcdn.com/image/fetch/$s_!BYVN!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18b54220-d42f-4f1e-b01e-1321de9d486c_1376x768.webp 1272w, https://substackcdn.com/image/fetch/$s_!BYVN!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18b54220-d42f-4f1e-b01e-1321de9d486c_1376x768.webp 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!BYVN!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18b54220-d42f-4f1e-b01e-1321de9d486c_1376x768.webp" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/18b54220-d42f-4f1e-b01e-1321de9d486c_1376x768.webp&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:51632,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/webp&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://journal.daniellopes.dev/i/145045678?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18b54220-d42f-4f1e-b01e-1321de9d486c_1376x768.webp&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!BYVN!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18b54220-d42f-4f1e-b01e-1321de9d486c_1376x768.webp 424w, https://substackcdn.com/image/fetch/$s_!BYVN!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18b54220-d42f-4f1e-b01e-1321de9d486c_1376x768.webp 848w, https://substackcdn.com/image/fetch/$s_!BYVN!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18b54220-d42f-4f1e-b01e-1321de9d486c_1376x768.webp 1272w, https://substackcdn.com/image/fetch/$s_!BYVN!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18b54220-d42f-4f1e-b01e-1321de9d486c_1376x768.webp 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a></figure></div><p>Context: In May I left my <a href="https://journal.daniellopes.dev/p/end-of-a-7-year-journey">full-time job</a> to start a 3-month LLM learning cycle by building a few products of my own. I&#8217;m documenting my journey here. Every week I post a recap of how the week went, things I learned, etc.</p><p>Had a bit of a shorter week. I went on a camping trip to Yosemite and had no service for 3 days. Despite this, still managed to pack 3 days of 10 hours.</p><p>Here's some of the progress and learnings:</p><h2>Canopy AI: JSON vs XML and streaming</h2><p>I'm still helping maintain the AI Assistant I built for <a href="https://canopy.is/">Canopy</a>. It has the usual Chat experience where a user asks a question, we do a RAG search and layer a bunch of things on top. </p><p>One frustrating aspect has been GPT-4's unreliability in returning JSON. OpenAI's Completion API has a JSON mode that ensures valid JSON output, but this option isn't available on the Assistant API when using the File Retrieval tool (their built-in RAG).</p><p>Although OpenAI's built-in RAG gives me better results compared to Pinecone and PG Vector, the trade-off for Canopy's use case was losing the JSON mode.</p><p>Canopy's assistant does more than just RAG the content. It runs categorization, sensitivity checks, confidence checks, and other tasks that might trigger subsequent LLM calls or be needed in the user interface. These constraints and extra information are metadata that I used to include in a JSON (making a single API call for speed and cost).</p><p>The problem with JSON is streaming. Ideally, you want to start rendering the message as you receive the response. In the JSON, I had a markdown answer as one of the values. I'd buffer the JSON until the right value starts streaming and relay that to the user interface, stopping when the value ends. A better solution would be to have the markdown first, followed by the metadata in a structured data format (JSON, XML, etc.). After a full day of prompt engineering, I couldn't consistently get GPT-4 to return the metadata in this format after the markdown message &#8211; until GPT-4o.</p><p>Last week, I spent a day migrating from the JSON format to a structure with markdown first, followed by the metadata inside XML. Anthropic uses XML in their examples, so I've been using this tip with OpenAI as well (makes sense if you think about it, it&#8217;s easier for transformers to handle words than curly braces).</p><p>The end format looks like this:</p><pre><code>Markdown answer&#8230;
```xml
&lt;metadata&gt;
&#8230;
&lt;/metadata&gt;
```</code></pre><p>Incorporating the ``` is another trick that took me a while to learn. When you can't use JSON mode, OpenAI will often add wrappers like these. Instead of trying to remove them in the prompt or handling failures in the app, including "shots" (examples) with the ``` as part of the answer will guide the model to always return it.</p><p>This simplified the code on our app side and made the metadata correct nearly 100% of the time. The next step is to auto-retry on the rare cases when it fails, which I haven't implemented yet.</p><h2>The New Product</h2><p>So far, in these 3 weeks, I've spent around 40 hours on the new product, with a significant portion of that time dedicated to boilerplate tasks that I won't need to repeat for future products, which is a positive.</p><p>While most of the AI work was already done, I couldn't resist adding some extra features at the last minute with GPT-4o. Scope creep? Why not!</p><p>I finally have a name &#8211;&nbsp;but I&#8217;ll share it once the landing page is up. Until now I had it under a code name, but now I have the final name, domain, and a marketing landing page 90% done.</p><p>Selecting the domain and name included initial SEO work. I think it&#8217;s BS that domains are not relevant for SEO anymore. If you are a nobody in page authority, I think it&#8217;s a good idea to make the domains very literal, so that&#8217;s how I&#8217;m starting: a short name followed by something literal.</p><p>In the 2 days I had after spending a day on Canopy, I worked on:</p><ul><li><p><strong>Feature work:</strong></p><ul><li><p>Refining the AI features and adding some extra parallel LLM calls.</p></li><li><p>Finished an Insights page (I hate styling Heatmaps).</p></li><li><p>Added dark mode support while stuck in traffic driving to Yosemite.</p></li><li><p>Started with a Telegram bot.</p></li></ul></li><li><p><strong>Marketing</strong></p><ul><li><p>Finished a landing page and registered the domain.</p></li><li><p>SEO: Research to find keywords I could try to rank for and figure out a strategy for evergreen content (I'll need more time here).</p></li></ul></li></ul><p>Before sharing the product with everyone, I still have to polish some final details, like setting up the Stripe account, deploying to the final servers, etc.</p><p><strong>Timeline-wise, I'm thinking I need:</strong></p><ul><li><p>1 more full week for polishing, details, and putting up the waitlist (including boring things like Terms of Service).</p></li><li><p>About 3 days for the initial marketing work, including backlink work, evergreen SEO-focused pages, and some community-based distribution.</p></li></ul><p>Then, I'm switching attention to the second product that I want for myself (while keeping 25% of my time on this one).</p><p>Once the product is live with users, I plan to share some of the lessons more openly by writing specific posts about certain things. </p><p>For example, on this project, I've been using a mix of multiple parallel LLM calls and OpenAI batch processing. These two things could be interesting as standalone posts. </p><p>I also hope to carve out time to write separate posts about some of the product and marketing aspects whenever I can.</p><h2>Week 4 Plan</h2><p>This week, I'll be splitting my work into three parts:</p><p>1 day for Canopy</p><p>2 days on New Product</p><p>3 days helping a friend with his startup (I usually work a 6-day week anyway)</p><p>I'm avoiding doing any kind of external work, but in this case, I made an exception. </p><p>It's a fixed-scope project on something I'm quite familiar with, plus it's an opportunity to learn some new React on a real product designed by great programmers. On top of that, what this friend is building is an impressive product in an interesting domain with a capable team, so I'll help whenever I can. I&#8217;m estimating probably 14 days on this (let&#8217;s see how off I&#8217;ll be this time).</p><p>This will delay my LLM learning cycle plan a bit, but it's a good trade-off.</p><p>I'll continue to share my updates here regardless.</p>]]></content:encoded></item><item><title><![CDATA[RANT: You're Using ChatGPT Wrong]]></title><description><![CDATA[This isn't polished tech where you can put in no effort and get results.]]></description><link>https://journal.daniellopes.dev/p/rant-youre-using-chatgpt-wrong</link><guid isPermaLink="false">https://journal.daniellopes.dev/p/rant-youre-using-chatgpt-wrong</guid><dc:creator><![CDATA[Daniel Lopes]]></dc:creator><pubDate>Wed, 22 May 2024 20:34:33 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/333bfe8f-0aa8-4bf0-a67b-445c015daeab_1376x768.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Most of the LLM criticism I see is easily fixable if people have a basic understanding of tech. OpenAI shares some blame for this, since their chat UI has become the standard but explains nothing and tries to be generic, leaning in on zero-shot to seem magical, leading to poor results out of the box. </p><p>Previously, people were using the inferior free GPT-3.5. With GPT-4o, there's no excuse for uninformed takes flooding social media and YouTube. OpenAI's terrible ChatGPT UI and closed-source GPT store are still problematic. <a href="https://docs.anthropic.com/en/prompt-library/library">At least Anthropic is trying to teach better prompt writing</a> (with more effort than OpenAI).</p><p>But back to my rant...</p><p>Many users do not try to tune the system, ask poorly written questions, get unsatisfactory results, and then complain online. We're 2 years into this cycle - it's time to wise up.</p><p>By now, we should all know that these systems are few-shot predictive models that respect the chain of command. Yet users provide neither the few-shot examples nor the command it should follow. It's no wonder ChatGPT-written resumes and landing pages sound like professional BS with poor English.</p><h4>To get good results, you need to:</h4><ol><li><p>Give it examples</p></li><li><p>Understand the chain of command</p></li></ol><h4>GPTs can handle Zero-shot and Few-shot (but not really)</h4><ul><li><p>Zero-shot learning: performing new tasks using broad pre-training</p></li><li><p>One-shot and few-shot learning: generalizing from 1-to-many examples to perform a task on new inputs</p></li></ul><p>While GPT should handle both, its zero-shot capabilities aren't there yet beyond toying around. Always provide 2-10 examples of what you want - otherwise, you'll get predictions based on general knowledge, which means bad results.</p><h3>The GPT Chain of Command</h3><ol><li><p>OpenAI and other providers set the basic rules and capabilities.</p></li><li><p>Developers can customize these settings for specific tasks.</p></li><li><p>End-user requests go through the customized settings.</p></li></ol><p>For non-developers, the best way to leverage the chain of command is to create a custom GPT with a system message specifying your requirements, along with necessary examples.</p><p>If you're coding against the APIs directly, you have more options beyond just system messages, such as fine-tuning. However, in the context of ChatGPT, system messages are the primary tool available (function calls and tags can be discussed in another post).</p><p>Tip: You can use Anthropic's prompt generator to create the initial system message and examples, then paste it into ChatGPT's custom GPT (Anthropic's UI is too bad to use directly): https://x.com/danielvlopes/status/1792978707201831155</p><p>Here's a simplified version of what I use for my Blog Posts custom GPT in ChatGPT:</p><pre><code># Identity 
You are a draft polisher assistant. Your job is to receive long-form poorly formatted drafts and convert them to a final version maintaining the tone, and vocabulary but using fewer words, fixing the grammar, adding more spacing, better structure, and making things clearer.

# Steps to take

To do this, first carefully read through the entire blog post to understand its structure and key points. Then, go through and rewrite the polished version of each section while keeping the same titles and technical insights.

Here are some tips:

- Remove unnecessarily complex language. Replace these with plain, straightforward terms. For example:
-- Instead of "leverage", use "use"  
-- Instead of "synergize", explain what you actually mean, like "work together"
-- Instead of "disintermediation", just explain the concept in simple terms
- Break up long, run-on sentences into shorter, clearer ones
- Use contractions like "it's" and "you'll" to make it sound more natural and conversational 
- Identify the technical parts of the text and don't remove these
- Keep the tone straightforward and professional, avoiding overly casual language but ensuring it doesn't become too formal.
- Keep the personal touch and original intent of the content.
- Format the condensed version of the post with clear section breaks and spacing for readability.

Here's a list of banned words to never ever use any of the following words (or similar words): "delve", "embarked", "journey", "thrilled", "aim", "tailored", "fledgling", "shrouded", "endeavor" , "quantifiable", "empirical", "whereabouts", "debut", "keen", "craft", "tailor", "elevate", "ignite", "empower", "unleash", "horizon", "harness", "diving into", "interconnect", "enhance".

As you write the new version, make sure to maintain the same voice, tone, vocabulary, and style as the original blog post. The goal is not to rewrite it completely, but to have a slight more polished version that is easily digestible format for people short on time.

# Example 1

Input: 
```
Original draft
```

Output: 
```
Well written version
```

# Example 2:

Input: 
```
Original draft
```

Output: 
```
Well written version
```

# Example 3:

Input: 
```
Original draft
```

Output: 
```
Well written version
```</code></pre><p>Put in some effort; otherwise, you are to blame for the bad results. With early-stage technology, we can't have the luxury of expecting things to work perfectly right out of the box.</p><p></p>]]></content:encoded></item><item><title><![CDATA[W2 Recap: 4o, TailwindUI, lot of code]]></title><description><![CDATA[Here's what I accomplished in my 2nd week of my 3-month build & learn cycle]]></description><link>https://journal.daniellopes.dev/p/week-2-recap-4o-tailwindui-lot-of</link><guid isPermaLink="false">https://journal.daniellopes.dev/p/week-2-recap-4o-tailwindui-lot-of</guid><dc:creator><![CDATA[Daniel Lopes]]></dc:creator><pubDate>Sat, 18 May 2024 19:05:20 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/a9183bb2-2e90-400a-8150-1857404a3f06_1376x768.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In May I left my <a href="https://journal.daniellopes.dev/p/end-of-a-7-year-journey">full-time job</a>  to start a 3-month LLM learning cycle by building a few products of my own. I&#8217;m documenting my journey here. Every week I post a recap of how the week went, things I learned, etc.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!6p0d!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd5618f2-2a07-4378-9eb7-7e3455ad165d_1376x768.webp" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!6p0d!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd5618f2-2a07-4378-9eb7-7e3455ad165d_1376x768.webp 424w, https://substackcdn.com/image/fetch/$s_!6p0d!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd5618f2-2a07-4378-9eb7-7e3455ad165d_1376x768.webp 848w, https://substackcdn.com/image/fetch/$s_!6p0d!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd5618f2-2a07-4378-9eb7-7e3455ad165d_1376x768.webp 1272w, https://substackcdn.com/image/fetch/$s_!6p0d!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd5618f2-2a07-4378-9eb7-7e3455ad165d_1376x768.webp 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!6p0d!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd5618f2-2a07-4378-9eb7-7e3455ad165d_1376x768.webp" width="1376" height="768" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/dd5618f2-2a07-4378-9eb7-7e3455ad165d_1376x768.webp&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:768,&quot;width&quot;:1376,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:56138,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/webp&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://journal.daniellopes.dev/i/144756013?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd5618f2-2a07-4378-9eb7-7e3455ad165d_1376x768.webp&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!6p0d!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd5618f2-2a07-4378-9eb7-7e3455ad165d_1376x768.webp 424w, https://substackcdn.com/image/fetch/$s_!6p0d!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd5618f2-2a07-4378-9eb7-7e3455ad165d_1376x768.webp 848w, https://substackcdn.com/image/fetch/$s_!6p0d!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd5618f2-2a07-4378-9eb7-7e3455ad165d_1376x768.webp 1272w, https://substackcdn.com/image/fetch/$s_!6p0d!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd5618f2-2a07-4378-9eb7-7e3455ad165d_1376x768.webp 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h3>Idea selection</h3><p>As <a href="https://journal.daniellopes.dev/i/144571357/why-now">I said before</a>, I'm currently focused on small indie-hacker-scoped projects. What does that mean? </p><p>I'm sorting ideas by level of scope and potential size. For the first projects, I'm avoiding super ambitious things, they need large surface area and tend to have a lot of competition. In the middle, there are &#8220;during gold rush, sell shovels&#8221; type of ideas, like AI infrastructure tools for developers where the need is clear, but so many teams are rushing to build them. </p><p>I'm looking for small things or those with seemingly bad business models that I want to use myself. When picking a market, you either solve something for yourself or others. For now, I'm choosing things I want for myself to save time on initial customer research. </p><p>However, I still want something with clusters of people easily found online so marketing isn&#8217;t an uphill battle.</p><p>To recap: I need something not hard to market with a bad <a href="https://en.wikipedia.org/wiki/Total_addressable_market">TAM</a>, small in scope, and that I want for myself (likely small apps, wrappers, or add-ons for existing players). </p><p><strong>Perfect recipe for disaster &#128517; Why?</strong> </p><ol><li><p>It gives me time to focus on adjacent things I'll reuse later, like a clean boilerplate with UI libraries, authentication, billing, and API clients.  </p></li><li><p>In this first month, I'm basically starting easy to rest a bit while staying creative, studying, and even having a chance to build some baby MRR (but very unlikely). </p></li></ol><p>I've narrowed my list down to 5 potential ideas for now, and I&#8217;m already working on a side project that I&#8217;ve had started in the past. These ideas will be for the next project.</p><h1>Week recap: progress!</h1><h3>Boilerplate</h3><h4>Rails &#128642;</h4><p>I'm sticking with Rails - it's stable, battle-tested, and I know it well. Not interested in Next.js yet, maybe just for marketing later.</p><p>Going with the vanilla Rails stack for now, using Hotwire instead of React for the front end. Everything has a learning curve, and modern-day React is one I don't want to tackle now. Might use React later for more interactive ideas.</p><h4>Jumpstart Pro &#128640;</h4><p>Didn't want to waste time setting up billing (even with Stripe), accounts, authentication, 2FA, or even little stuff like pagination. Went with <a href="https://jumpstartrails.com">Jumpstart Pro</a> - it's a good starting point with high-quality code that's easy to customize, even if I'd prefer a smaller and with less dependencies. JSP also has a lot of new things that I wasn&#8217;t familiar with like <a href="https://code.visualstudio.com/docs/devcontainers/containers">Dev Containers</a>, so fun learning experience.</p><p></p><h4>TailwindCSS + TailwindUI (Pros &amp; Cons) &#127788;&#65039;</h4><p>Switched from theming Bootstrap (like I did for Canopy) to TailwindUI. Not having CSS files makes it perfect for code generators like custom ChatGPT and V0, which are great at generating Tailwind markup. TailwindUI is also very versatile and covers a lot, so I get a productive boost from the (copy, paste, and customize).</p><p>However, using TailwindUI with vanilla Rails hasn't been smooth. I find myself coding basic things because TailwindUI has no vanilla JS option for behaviors like dropdowns, carousels, and off-canvas panels. Jumpstart's Stimulus helps with some of that. Another issue is that TailwindUI's markup was meant for React components, so you often need to abstract classes into Rails helpers for repetitive use.</p><p>This week: 2 days spent to cover TailwindUI basics, 1 day to learn Jumpstart, and the learning curve of TailwindCSS every day. But now feeling quite productive already.</p><h3>Brainstorming with friends</h3><p>I have a lot of people reaching out to network and brainstorm ideas. Last week I spent about &amp; hours on this.</p><h4>Canopy: GPT-4o</h4><p>I work 8 hours a week at Canopy, doing 1-2 hours at a time. After OpenAI launched GPT-4o, I migrated our AI Assistant:</p><ul><li><p>It's much <strong>cheaper and faster</strong> (so fast that streaming isn&#8217;t necessary anymore)</p></li><li><p>Overall <strong>better results</strong>: I tested using our rubric of 200 questions (not a formal eval system yet). After migration, the results were mostly better.</p></li></ul><p><strong>Two small issues:</strong></p><ol><li><p><strong>Acronyms:</strong> It made up some acronyms, which I fixed with prompt engineering.</p></li><li><p><strong>JSON</strong>: We use OpenAI's Assistant API with their RAG tool, so we can't use "JSON MODE". I ask for JSON via prompt engineering. It tried to add a wrapper around the markdown to avoid breaking the JSON, which we fixed by adjusting the code.</p></li></ol><p>The <strong>speed and price drop let us split our 200+ line prompt into two prompts</strong>, running the query sequentially:</p><ol><li><p>Ask for the answer, present it to the user</p></li><li><p>Ask for additional metadata async and refresh that part of the screen (WIP, shipping next week)</p></li></ol><p>The cost drop opens up the opportunity to use GPT-4 level of IQ for everything, including B2C customers with low subscription prices.</p><h4>Product 1: A Lot of Work Done</h4><p>As I said before, I'm already working on my first product, which I've been building since early this year a few hours a week. It's a small thing, but a useful tool for myself that benefits from LLM support.</p><p>I spent 3 days (30 hours) migrating the code to Jumpstart Pro and 4o, and adding features for launch - shooting for next weekend. I also worked on the marketing landing page.</p><p><strong>Still to do: </strong>Complete an &#8220;insights&#8221;  feature. Add an LLM-powered overview screen. TailwindUI is helping a lot with the design. So, I&#8217;m estimating ~3 to 5 more days before able to onboard users.</p><p>I&#8217;ll need to setup new servers due to significant changes from Jumpstart Pro. Setting up servers again will take likely at most one day.</p><p>Goal:  For this week or next, put the product up + add a marketing landing with a waitlist, and send it to the communities I&#8217;m a member of.</p><h2>The bad things</h2><ol><li><p><strong>Poor sleep hygiene:</strong> Worked too close to bed, messing up my sleep. Getting older I need to be a lot smarter about sleep hygiene these days or the price is real.</p></li><li><p><strong>Not enough exercise:</strong> Only exercised 3 times: 2x 40min half-assed weight sessions, 45min hard VO2 max virtual cycling race on Zwift. Usually do 2x that, it's important for my mental health.</p></li><li><p><strong>Missed meet-ups:</strong> Trying to go to more. Had two interesting ones this week, an Agent Guidance and a Gemini vs 4o Hackathon on Saturday, and skipped both.</p></li></ol><h2>Next week</h2><p>I'm off for 3 days on a last-minute camping trip, so this week will be short. Working this weekend to account for it. Most of my time will be split between working on Product 1 and some LLM work for Canopy.</p><p></p>]]></content:encoded></item><item><title><![CDATA[Week 1 Recap: Ideas, Boilerplate, Monitoring & (not) Shipping]]></title><description><![CDATA[Here's what I accomplished in my first week of my 3-month build & learn cycle]]></description><link>https://journal.daniellopes.dev/p/week-1-recap-ideas-boilerplate-monitoring</link><guid isPermaLink="false">https://journal.daniellopes.dev/p/week-1-recap-ideas-boilerplate-monitoring</guid><dc:creator><![CDATA[Daniel Lopes]]></dc:creator><pubDate>Mon, 13 May 2024 07:12:38 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/8b223d29-c1b8-4607-ae5a-c66870cc1506_1376x768.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!4mTD!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc69c94f4-26e3-45da-acc2-7af262858c55_1376x768.webp" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!4mTD!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc69c94f4-26e3-45da-acc2-7af262858c55_1376x768.webp 424w, https://substackcdn.com/image/fetch/$s_!4mTD!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc69c94f4-26e3-45da-acc2-7af262858c55_1376x768.webp 848w, https://substackcdn.com/image/fetch/$s_!4mTD!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc69c94f4-26e3-45da-acc2-7af262858c55_1376x768.webp 1272w, https://substackcdn.com/image/fetch/$s_!4mTD!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc69c94f4-26e3-45da-acc2-7af262858c55_1376x768.webp 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!4mTD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc69c94f4-26e3-45da-acc2-7af262858c55_1376x768.webp" width="1376" height="768" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c69c94f4-26e3-45da-acc2-7af262858c55_1376x768.webp&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:768,&quot;width&quot;:1376,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:19254,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/webp&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://journal.daniellopes.dev/i/144571357?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc69c94f4-26e3-45da-acc2-7af262858c55_1376x768.webp&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!4mTD!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc69c94f4-26e3-45da-acc2-7af262858c55_1376x768.webp 424w, https://substackcdn.com/image/fetch/$s_!4mTD!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc69c94f4-26e3-45da-acc2-7af262858c55_1376x768.webp 848w, https://substackcdn.com/image/fetch/$s_!4mTD!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc69c94f4-26e3-45da-acc2-7af262858c55_1376x768.webp 1272w, https://substackcdn.com/image/fetch/$s_!4mTD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc69c94f4-26e3-45da-acc2-7af262858c55_1376x768.webp 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>I've been toying with LLMs since end of 2022, trying to create an AI Assistant for my company, <a href="https://canopy.is/">Canopy</a>. The tech wasn&#8217;t quite there until GPT-4 came along. Last week, after launching our AI Assistant in alpha, I decided to leave <a href="https://journal.daniellopes.dev/p/end-of-a-7-year-journey">my job to focus on developing my own ideas</a>. I&#8217;ll be documenting my journey here as I go, and this is the recap of my first week.</p><h4>Why now?</h4><p>With the last couple of years' progress, so many of the traditional ML projects have been (or could be) replaced by language models, making things easier compared to just three years ago. Things like unstructured data, classification, sentiment analysis, NLP, speech, and much more are now all manageable by one person or a tiny team.</p><p>I think there are four ways to benefit from what is happening:</p><ol><li><p>Big Tech working on foundational infrastructure or large problems.</p></li><li><p>Moonshot projects challenging existing players like Perplexity vs Google.</p></li><li><p>Vertical applications (or what people are now calling "Applied AI").</p></li><li><p>Indie hackers focused on things that don't look venture-scale at first glance.</p></li></ol><p>For now, for these next three months, I'm personally interested in item 4. Maybe later I'll try to join a team working on the other ones.</p><h4>Setting a 3-month deadline</h4><p>Having a short deadline helps keep me motivated and accountable. It pushes me to focus on practical, achievable goals. </p><p>Since I work in product and not ML or research, I'm interested in end-use application. There's a ton of effort involved in making LLMs (unstable, unreliable &amp; expensive tech) work smoothly in a finished product. </p><p>For instance, if I were only studying, factors like accuracy, cost, or user experience would be glossed over. But if I need to ship and charge for something, that&#8217;s the opposite.</p><p>Three months, with my skill set, I think is a doable but still challenging timeline to ship at least two products (my stretch goal is six).</p><h1>Now, to the first-week recap</h1><p><strong>I had 5 goals for this past week:</strong></p><ol><li><p>Ship my personal site, start a Substack, clean up social media. </p></li><li><p>Get a boilerplate codebase for my projects (sign-up, subscription, etc).</p></li><li><p>Organize and research my ideas: pick 3 to 6. </p></li><li><p>Canopy: monitor the Alpha launch of our AI Assistant.</p></li><li><p>Bonus: Ship a WIP project that I had already.</p></li></ol><h3>&#9989; Goal 1: Personal site, Substack &amp; social media</h3><p><strong>Personal site:</strong> Over the weekend, I started working on a personal site that I&#8217;d need to send to some people. I also used it to play with Next, Vite, Astro, Tailwind, and Shadcn. All things not part of Canopy stack. </p><p>I went with Next + TailwindUI. Site is live here: <a href="https://daniellopes.dev">https://daniellopes.dev</a></p><p>For my products will be using just Tailwind and my usual Rails.</p><p><strong>Substack:</strong> <a href="https://notes.andymatuschak.org/zCMhncA1iSE74MKKYQS5PBZ">Working with the garage door open is something</a> I always wanted to do for <a href="https://canopy.is/">Canopy</a>, but I left that for my co-founder. So, last week I started this, and I posted the first post: <a href="https://journal.daniellopes.dev/p/parsing-7-years-of-stand-up-updates">Using LLMs to parse 7 years of stand-up updates</a> (which was an exercise in trying different summarization approaches as well). </p><p>Writing a ton is also part of one of my ideas that I might work on next month.</p><p><strong>Social media: </strong>To stay more informed about things happening in San Francisco (meetups, hackathons, etc). So spent a few hours making list of people I want to follow more closely. Social media isn't all just noise; it can be valuable.</p><h3>&#129000; Goal 2: Organize all my ideas</h3><p>I made a lot of progress on this goal, but not enough to confidently have three solid ones. I'll keep working on this next week. Here's the gist:</p><p>I keep a list of ideas, logging anything that comes to mind (features or products). I always have anywhere around 100 to 200 items.</p><p>This week, primary goal was to organize my list, considering these 4 criteria:</p><ul><li><p><strong>Is it a newly viable thing?</strong> And is it flooded with people doing good work already? (Areas like Knowledge Base for Companies or Customer Support are already saturated.)<br></p></li><li><p><strong>Do I want this for myself? </strong>Building something for others demands a lot of research, which isn't feasible within a three-month timeline.<br></p></li><li><p><strong>Does it have commercial potential?</strong></p><ul><li><p><strong>If no commercial potential</strong>, the aim should be for learning or personal use; don't waste time on unviable or <a href="https://matt-rickard.com/tarpit-ideas">tarpit</a> ideas. Do just enough to meet the goal and move on. At the end of the day, I want people to use the things I build.</p></li><li><p><strong>If there's commercial potential, </strong>do I have a unique perspective on solving the challenges? Then do the usual analysis&#8212;pricing, customer base needed for a MRR, competitors, etc.<br></p></li></ul></li><li><p>Does it have the <strong>potential to find a single feature</strong> that could be a lot better than existing methods? And can it be developed as an add-on for existing players or does it need to be a replacement? (replacements are less interesting with this timeline).<br></p></li><li><p><strong>What&#8217;s the marketing effort? Can I market it alone?</strong> If it's B2B, can I identify a sustainable group of people to target? If it's B2C, can I come up with marketing strategies that don't rely on ads or require excessive time?</p></li></ul><p>Many ideas I had on the list from last year had no credible competitors six months ago, but now have promising ones. So, I ditched those. While I don't mind competition when working with more resources, working solo, I don&#8217;t need my back against the wall all the time.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!l4d7!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fccb3aa00-ff5b-4629-a51c-28acab3070e0_3662x2626.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!l4d7!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fccb3aa00-ff5b-4629-a51c-28acab3070e0_3662x2626.png 424w, https://substackcdn.com/image/fetch/$s_!l4d7!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fccb3aa00-ff5b-4629-a51c-28acab3070e0_3662x2626.png 848w, https://substackcdn.com/image/fetch/$s_!l4d7!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fccb3aa00-ff5b-4629-a51c-28acab3070e0_3662x2626.png 1272w, https://substackcdn.com/image/fetch/$s_!l4d7!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fccb3aa00-ff5b-4629-a51c-28acab3070e0_3662x2626.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!l4d7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fccb3aa00-ff5b-4629-a51c-28acab3070e0_3662x2626.png" width="1456" height="1044" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ccb3aa00-ff5b-4629-a51c-28acab3070e0_3662x2626.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1044,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:385072,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!l4d7!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fccb3aa00-ff5b-4629-a51c-28acab3070e0_3662x2626.png 424w, https://substackcdn.com/image/fetch/$s_!l4d7!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fccb3aa00-ff5b-4629-a51c-28acab3070e0_3662x2626.png 848w, https://substackcdn.com/image/fetch/$s_!l4d7!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fccb3aa00-ff5b-4629-a51c-28acab3070e0_3662x2626.png 1272w, https://substackcdn.com/image/fetch/$s_!l4d7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fccb3aa00-ff5b-4629-a51c-28acab3070e0_3662x2626.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">I&#8217;m organizing all the ideas with Obsidian Kanban plugin, and the things in purple have some research around.</figcaption></figure></div><h3>&#9989; Goal 3: Boilerplate</h3><p>Initially, I planned to use much of Canopy's codebase for non-proprietary elements and create a standard boilerplate things like sign-up, subscriptions, and admin (which would let me contribute back improvements). </p><p>However, given my time constraints, I'm reluctant to spend excessive time cleaning things like our complex billing system that covers B2B, B2C, and enterprise solutions.</p><p>I've decided to go with <a href="https://jumpstartrails.com">Jumpstart Pro</a>. There are several things I plan to remove/change, but for now, it's enough. I&#8217;ve also wanted to learn Tailwind for a while, so it was nice that Jumpstart Pro came with Tailwind already.</p><p>I&#8217;m also sticking to Rails (<a href="https://world.hey.com/dhh/the-one-person-framework-711e6318">The One Person Framework</a> &#8482;&#65039;). </p><p>I&#8217;ve been tempted to make the jump to Python because of how readily available tooling is for their ecosystem, but the fastest way to ship nothing is to pick a bunch of things you are not expert on. It&#8217;s too easy to underestimate all the ecosystem details that you need to know in order to ship a product that is stable enough to require nearly no-maintenance.</p><p>In this case, my goal is to focus on the behavior of LLMs (different models, prompt architecture, cost, reliability, etc.) and not mess around with different frontend or backend technologies.</p><h3>&#9989; Goal 4: Canopy - Monitor the Alpha of AI Assistant</h3><p>We launched our AI Assistant in Alpha last week. So, I focused on getting visibility for how the system is performing. We haven't fully committed to an evaluation strategy yet. For now, we managed to see how satisfied people are, along with some basic analytics and reporting on content that we didn't have for <a href="https://blogs.nvidia.com/blog/what-is-retrieval-augmented-generation/">RAG</a>.</p><p>For &#8220;eval&#8221; this looks very promising: <a href="https://athina.ai">https://athina.ai</a></p><p>I&#8217;ve seen their product at a meet-up in SF last week and found it a better fit for our needs than other tools I'd considered (open source solutions like <a href="https://github.com/openai/evals">OpenAI</a>&#8217;s or <a href="https://ragas.io">Ragas</a>.)</p><h3>&#10060; Goal 5: Ship a WIP product</h3><p>I didn't succeed with this one. </p><p>Last year, I started working on a product that solves a personal use. None of the business calculations add up (cost per person vs what I can charge, TAM, competitors, etc.), but it meets my criteria of being something I want to use and something I can learn from. </p><p>I've already learned a lot from this project. It's what I worked on over the weekends last year to learn different models, prompting or RAG architecture without getting burnt out from just working at Canopy. It's ~80% done, but now I just need the last stretch to make it possible for others to sign up &amp; buy it so I'm not paying for other people's API calls. </p><p>I'll probably need another three days to get it ready for other users. Since I chose Jumpstart Pro, I'm going to migrate the product to it and see how that goes. So, this will carry over into Week 2.</p><h2>Plan for Week 2 </h2><p>Switching jobs, picking ideas, setting up the basics, and wrapping up existing projects is kind of like tying up loose ends. It's not the most thrilling, but it's still important.</p><p>For next week, I have 3 main goals: Launch (1) and market (2) the project I just mentioned, and to do more research on my ideas (3).</p>]]></content:encoded></item><item><title><![CDATA[Using ChatGPT & Custom GPTs for code brainstorming]]></title><description><![CDATA[As part of my attempt to get better at prompt engineering I'm really trying to do as much as possible of my work with some AI support (coding, design, reviews, copy, etc.]]></description><link>https://journal.daniellopes.dev/p/using-chatgpt-custom-gpts-for-code</link><guid isPermaLink="false">https://journal.daniellopes.dev/p/using-chatgpt-custom-gpts-for-code</guid><dc:creator><![CDATA[Daniel Lopes]]></dc:creator><pubDate>Fri, 10 May 2024 19:06:15 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!w3C0!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7763b1cc-1e8b-4e99-baa1-ac9ef8191a1c_4224x2494.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>As part of my attempt to get better at prompt engineering I'm really trying to do as much as possible of my work with some AI support (coding, design, reviews, copy, etc. use it for everything first).</p><p>Custom GPTs is the feature from ChatGPT that makes me use it more than anything else (more than Claude, Perplexity, or Gemini). I have a handful Custom GPTs that I use every day, and I create a bunch for specific needs as well. </p><p>One of my favorite use cases for one of my recurring Custom GPTs is to brainstorm different solutions before I start coding (this one is using a <a href="https://chatgpt.com/g/g-ZoyP3Ze9L-ruby-rails-helper">Rails-specific GPT</a> one). I pretty much will start planning my work there. It will often give me good suggestions or at least provide me with some good naming for things. Then at the end a finish by asking for a review as well.</p><p>In this example, I know what different patterns I might want to use here. I could do it myself no problem, but I find it great to be able to see a draft version of all the different ideas in 5 seconds first and then decide whether to try to do it in my head, picking just one and spending 20 minutes executing on it.</p><h1>The request</h1><pre><code>I need to reuse these lines on a different controller. What would you suggest? Maybe should I extract a service or PORO class? or a concern for controllers?

@learning_path = current_person.personal_learning_path
@learning_path_modules = @learning_path.training_modules.includes(:lessons) if @learning_path
@learning_path_progress = @learning_path.progress_for(current_person) if @learning_path
@training_modules = load_training_modules

---

def load_training_modules
  if current_organization_training_subscription&amp;.trial?
    TrainingModule.standard_order_for_trial
  else
    TrainingModule.preferred_order_for(
      current_person,
      order_by_preference: "recommendations",
      exclude_seen_modules: false,
      consider_watched_lessons: true,
      alternate_results: false
    )
  end
end

====HERES THE FULL CONTROLLER=====

class TrainingModulesController &lt; TrainingBaseController
  menu_item :training_modules
  before_action :initial_breadcrumbs

  def index
    @assessment = current_person.last_assessment_with_self_response_complete
    current_person.generate_personal_learning_path_if_needed!

    @learning_path = current_person.personal_learning_path
    @learning_path_modules = @learning_path.training_modules.includes(:lessons) if @learning_path
    @learning_path_progress = @learning_path.progress_for(current_person) if @learning_path

    @training_modules = load_training_modules
    @display_tour = !current_navigation_preference.learning_paths_tour_closed?
  end

  def show
    @training_module = TrainingModule.includes(:lessons).find(params[:id])
    @progress = TrainingModuleProgress.new(current_person, @training_module)
    @lesson = @progress.next_available_lesson || @training_module.lessons.first

    current_person.training_history_entries.track(request.url, @training_module)

    redirect_to training_module_lesson_path(@training_module, @lesson)
  end

  private

  def initial_breadcrumbs
    breadcrumb.add "Modules", training_modules_path
  end

  def load_training_modules
    if current_organization_training_subscription&amp;.trial?
      TrainingModule.standard_order_for_trial
    else
      TrainingModule.preferred_order_for(
        current_person,
        order_by_preference: "recommendations",
        exclude_seen_modules: false,
        consider_watched_lessons: true,
        alternate_results: false
      )
    end
  end
end</code></pre><h1>GPT Response</h1><p>Given the repetitive use of the code involved in fetching and preparing `@learning_path` and related entities across different controller actions, extracting these operations into a reusable component is a good idea. This will help maintain DRY (Don't Repeat Yourself) principles and ensure cleaner and more maintainable code. Here are a few options to consider:</p><p>### 1. Service Object</p><p>A service object is ideal for encapsulating business logic that doesn't naturally fit within a model or a controller. Since your code involves preparing data for views based on user-specific and contextual business rules, a service object could be a good fit.</p><pre><code># app/services/learning_path_service.rb
class LearningPathService
  def initialize(person)
    @person = person
  end

  def fetch_data
    learning_path = @person.personal_learning_path
    {
      learning_path: learning_path,
      learning_path_modules: learning_path&amp;.training_modules&amp;.includes(:lessons),
      learning_path_progress: learning_path&amp;.progress_for(@person),
      training_modules: load_training_modules
    }
  end

  private

  def load_training_modules
    if @person.current_organization_training_subscription&amp;.trial?
      TrainingModule.standard_order_for_trial
    else
      TrainingModule.preferred_order_for(
        @person,
        order_by_preference: "recommendations",
        exclude_seen_modules: false,
        consider_watched_lessons: true,
        alternate_results: false
      )
    end
  end
end</code></pre><p>Usage in a controller:</p><pre><code>def index
  service = LearningPathService.new(current_person)
  data = service.fetch_data
  @learning_path, @learning_path_modules, @learning_path_progress, @training_modules = data.values_at(:learning_path, :learning_path_modules, :learning_path_progress, :training_modules)
  @display_tour = !current_navigation_preference.learning_paths_tour_closed?
end</code></pre><p>### 2. Concern</p><p>If the logic is tightly coupled with ActiveRecord objects or used across multiple controllers, creating a concern might be a better approach. This keeps controller-specific logic within the context of controllers.</p><pre><code># app/controllers/concerns/learning_path_loadable.rb

module LearningPathLoadable
  extend ActiveSupport::Concern

  def load_learning_path_data
    @learning_path = current_person.personal_learning_path
    @learning_path_modules = @learning_path&amp;.training_modules&amp;.includes(:lessons)
    @learning_path_progress = @learning_path&amp;.progress_for(current_person)
    @training_modules = load_training_modules
  end

  private

  def load_training_modules
    if current_organization_training_subscription&amp;.trial?
      TrainingModule.standard_order_for_trial
    else
      TrainingModule.preferred_order_for(
        current_person,
        order_by_preference: "recommendations",
        exclude_seen_modules: false,
        consider_watched_lessons: true,
        alternate_results: false
      )
    end
  end
end</code></pre><p>Usage in a controller:</p><pre><code>class TrainingModulesController &lt; TrainingBaseController
  include LearningPathLoadable

  def index
    load_learning_path_data
    @display_tour = !current_navigation_preference.learning_paths_tour_closed?
  end
end</code></pre><p>### Decision</p><p>The choice between a service object and a concern depends on how closely the logic is tied to the controller's responsibilities. If the logic is more about data manipulation and less about HTTP-specific operations, a service object is more suitable. If it's about setting up controller instance variables and integrates closely with controller lifecycle (like before actions), a concern might work better. In your case, either approach would streamline your code and enhance maintainability, with a slight preference for a service object given the nature of the logic involved.</p><h1>Final decision</h1><p>I ended up with the concern approach with a code that is very similar to the original GPT suggestion.</p><h1>Custom GPT &#8220;source code&#8221;</h1><p>This custom GPT is the one I use for <a href="https://canopy.is">Canopy</a> setup for the following use cases (and a has few examples of our codebase inside):</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!w3C0!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7763b1cc-1e8b-4e99-baa1-ac9ef8191a1c_4224x2494.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!w3C0!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7763b1cc-1e8b-4e99-baa1-ac9ef8191a1c_4224x2494.png 424w, https://substackcdn.com/image/fetch/$s_!w3C0!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7763b1cc-1e8b-4e99-baa1-ac9ef8191a1c_4224x2494.png 848w, https://substackcdn.com/image/fetch/$s_!w3C0!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7763b1cc-1e8b-4e99-baa1-ac9ef8191a1c_4224x2494.png 1272w, https://substackcdn.com/image/fetch/$s_!w3C0!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7763b1cc-1e8b-4e99-baa1-ac9ef8191a1c_4224x2494.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!w3C0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7763b1cc-1e8b-4e99-baa1-ac9ef8191a1c_4224x2494.png" width="1456" height="860" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7763b1cc-1e8b-4e99-baa1-ac9ef8191a1c_4224x2494.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:860,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:4267008,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!w3C0!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7763b1cc-1e8b-4e99-baa1-ac9ef8191a1c_4224x2494.png 424w, https://substackcdn.com/image/fetch/$s_!w3C0!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7763b1cc-1e8b-4e99-baa1-ac9ef8191a1c_4224x2494.png 848w, https://substackcdn.com/image/fetch/$s_!w3C0!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7763b1cc-1e8b-4e99-baa1-ac9ef8191a1c_4224x2494.png 1272w, https://substackcdn.com/image/fetch/$s_!w3C0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7763b1cc-1e8b-4e99-baa1-ac9ef8191a1c_4224x2494.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div class="github-gist" data-attrs="{&quot;innerHTML&quot;:&quot;<div id=\&quot;gist130179441\&quot; class=\&quot;gist\&quot;>\n    <div class=\&quot;gist-file\&quot; translate=\&quot;no\&quot; data-color-mode=\&quot;light\&quot; data-light-theme=\&quot;light\&quot;>\n      <div class=\&quot;gist-data\&quot;>\n        <div class=\&quot;js-gist-file-update-container js-task-list-container\&quot;>\n  <div id=\&quot;file-rails_gpt-txt\&quot; class=\&quot;file my-2\&quot;>\n    \n    <div itemprop=\&quot;text\&quot; class=\&quot;Box-body p-0 blob-wrapper data type-text  \&quot;>\n\n        \n<div class=\&quot;js-check-bidi js-blob-code-container blob-code-content\&quot;>\n\n  <template class=\&quot;js-file-alert-template\&quot;>\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash flash-warn flash-full d-flex flex-items-center\&quot;>\n  <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n    <span>\n      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.\n      <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.co/hiddenchars\&quot; target=\&quot;_blank\&quot;>Learn more about bidirectional Unicode characters</a>\n    </span>\n\n\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash-action\&quot;>        <a href=\&quot;{{ revealButtonHref }}\&quot; data-view-component=\&quot;true\&quot; class=\&quot;btn-sm btn\&quot;>    Show hidden characters\n</a>\n</div>\n</div></template>\n<template class=\&quot;js-line-alert-template\&quot;>\n  <span aria-label=\&quot;This line has hidden Unicode characters\&quot; data-view-component=\&quot;true\&quot; class=\&quot;line-alert tooltipped tooltipped-e\&quot;>\n    <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n</span></template>\n\n  <table data-hpc class=\&quot;highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file\&quot; data-tab-size=\&quot;8\&quot; data-paste-markdown-skip data-tagsearch-lang=\&quot;Text\&quot; data-tagsearch-path=\&quot;rails_gpt.txt\&quot;>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L1\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;1\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC1\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;># IDENTITY and PURPOSE</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L2\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;2\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC2\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>You are Ruby on Rails programming assistant specialized in Ruby 3, Rails 7, Postgres Stimulus.js, Bootstrap 5, ERB, and Minitest. </td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L3\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;3\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC3\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L4\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;4\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC4\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;># STEPS TO FOLLOW</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L5\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;5\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC5\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L6\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;6\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC6\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>1. You have 5 modes, and you adjust your behavior based on each:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L7\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;7\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC7\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>1.1 Coding mode: the user asks for you to write code, you parse the request, and focus on output code snippets. DONT EXPLAIN anything, just write the code.</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L8\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;8\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC8\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>1.2 BRAINSTORM: the user asks for you to help brainstorm a feature, in this mode you mix code snippets with explanation.</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L9\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;9\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC9\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>1.3 DEBUG: the user asks for you to help debug a feature, in this mode you mix code snippets with explanation.</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L10\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;10\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC10\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>1.4 TEST: the user gives you a class (Controller or Model), and you write the test in Minitest following Rails conventions.</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L11\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;11\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC11\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>1.5 REVIEW: the user gives you a class, you review it, and make suggestions with code snippets included.</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L12\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;12\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC12\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L13\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;13\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC13\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>REALLY IMPORTANT: in Coding &amp;amp; Testing mode, you really avoid explaining anything, you just write code. In Brainstorming &amp;amp; Debugging mode, you mix code snippets with explanation but you avoid writing long paragraphs.</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L14\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;14\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC14\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L15\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;15\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC15\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>## TONE AND STYLE</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L16\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;16\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC16\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L17\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;17\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC17\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>You adhere to Rails naming conventions for classes, methods, and more as in you follow snake case for files and methods and camelcase for Classes. You also follow the Rails style guide for code formatting. You follow Rubocop rules.</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L18\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;18\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC18\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L19\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;19\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC19\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>## STYLE OF CODE YOU SHOULD WRITE</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L20\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;20\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC20\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L21\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;21\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC21\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>Example: Stimulus Controller (make sure to avoid addEventListeners, instead favor interactions via HTML actions, values, and targets)</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L22\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;22\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC22\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L23\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;23\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC23\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>import { Controller } from &amp;quot;@hotwired/stimulus&amp;quot;;</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L24\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;24\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC24\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>import { install } from &amp;quot;@github/hotkey&amp;quot;;</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L25\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;25\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC25\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L26\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;26\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC26\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>export default class extends Controller {</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L27\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;27\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC27\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>  connect() {</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L28\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;28\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC28\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    this.installHotkeys();</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L29\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;29\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC29\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>  }</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L30\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;30\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC30\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L31\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;31\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC31\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>  disconnect() {</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L32\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;32\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC32\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    this.uninstallHotkeys();</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L33\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;33\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC33\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>  }</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L34\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;34\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC34\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L35\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;35\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC35\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>  installHotkeys() {</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L36\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;36\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC36\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    for (const el of this.element.querySelectorAll(&amp;quot;[data-hotkey]&amp;quot;)) {</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L37\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;37\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC37\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>      install(el);</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L38\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;38\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC38\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    }</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L39\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;39\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC39\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>  }</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L40\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;40\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC40\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L41\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;41\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC41\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>  uninstallHotkeys() {</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L42\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;42\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC42\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    for (const el of this.element.querySelectorAll(&amp;quot;[data-hotkey]&amp;quot;)) {</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L43\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;43\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC43\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>      el.hotkey?.destroy(); // Only works if hotkey exposes a destroy/uninstall method</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L44\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;44\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC44\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    }</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L45\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;45\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC45\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>  }</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L46\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;46\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC46\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>}</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L47\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;47\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC47\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L48\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;48\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC48\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>Example: Rails Controller</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L49\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;49\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC49\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L50\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;50\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC50\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>class AssessmentsController &amp;lt; TrainingBaseController</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L51\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;51\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC51\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>  before_action :disable_training_search</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L52\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;52\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC52\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>  before_action :find_in_progress_or_start_new, only: %i[new create new_via_signup]</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L53\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;53\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC53\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L54\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;54\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC54\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>  def new_via_signup</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L55\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;55\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC55\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    if @assessment.persisted?</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L56\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;56\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC56\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>      @response = find_or_create_response_for(@assessment)</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L57\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;57\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC57\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L58\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;58\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC58\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>      if @response.complete?</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L59\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;59\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC59\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        redirect_to training_home_path, status: :see_other</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L60\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;60\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC60\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>      end</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L61\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;61\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC61\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    end</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L62\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;62\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC62\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>  end</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L63\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;63\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC63\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L64\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;64\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC64\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>  def new</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L65\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;65\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC65\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    if @assessment.persisted?</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L66\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;66\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC66\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>      @response = find_or_create_response_for(@assessment)</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L67\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;67\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC67\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L68\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;68\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC68\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>      if @response.complete?</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L69\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;69\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC69\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        redirect_to assessment_results_path(@assessment), status: :see_other</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L70\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;70\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC70\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>      end</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L71\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;71\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC71\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    else</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L72\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;72\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC72\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>      @last_assessment = current_person.assessments.order(created_at: :desc).first</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L73\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;73\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC73\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    end</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L74\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;74\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC74\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>  end</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L75\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;75\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC75\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L76\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;76\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC76\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>  def create</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L77\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;77\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC77\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    @assessment.survey = current_organization.assessment_surveys.first!</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L78\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;78\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC78\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    @assessment.onboarding_assessment = params[:assessment]&amp;amp;.fetch(:onboarding_assessment).present?</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L79\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;79\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC79\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L80\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;80\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC80\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    ActiveRecord::Base.transaction do</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L81\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;81\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC81\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>      @assessment.save!</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L82\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;82\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC82\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>      @response = find_or_create_response_for(@assessment)</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L83\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;83\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC83\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>      track(&amp;quot;assessment_created&amp;quot;,</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L84\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;84\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC84\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>            assessment_id: @assessment.id,</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L85\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;85\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC85\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>            onboarding_assessment: @assessment.onboarding_assessment)</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L86\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;86\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC86\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    end</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L87\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;87\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC87\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L88\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;88\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC88\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    redirect_to next_assessment_response_answers_path(@response), status: :see_other</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L89\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;89\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC89\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>  end</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L90\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;90\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC90\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L91\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;91\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC91\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>  private</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L92\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;92\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC92\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L93\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;93\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC93\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>  def find_or_create_response_for(assessment)</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L94\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;94\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC94\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    response = assessment.responses.find_by(author: current_person)</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L95\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;95\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC95\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    response ||= assessment.responses.incomplete.find_or_create_by!(author: current_person)</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L96\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;96\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC96\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L97\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;97\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC97\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    response</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L98\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;98\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC98\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>  end</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L99\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;99\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC99\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L100\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;100\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC100\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>  def find_in_progress_or_start_new</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L101\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;101\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC101\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    @assessment = if current_person.assessments.open.any?</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L102\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;102\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC102\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>                    current_person.assessments.open.first</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L103\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;103\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC103\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>                  else</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L104\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;104\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC104\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>                    current_person.assessments.new</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L105\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;105\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC105\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>                  end</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L106\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;106\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC106\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>  end</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L107\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;107\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC107\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>end</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L108\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;108\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC108\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L109\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;109\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC109\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>Example: Rails View</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L110\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;110\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC110\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L111\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;111\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC111\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>&amp;lt;header class=&amp;quot;hero-header border-bottom overflow-hidden&amp;quot; data-controller=&amp;quot;&amp;lt;%= &amp;quot;turbo-cache-clear&amp;quot; if params[:expire].present? %&amp;gt;&amp;quot;&amp;gt;</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L112\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;112\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC112\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>  &amp;lt;div class=&amp;quot;container pt-4 pt-md-5&amp;quot;&amp;gt;</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L113\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;113\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC113\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    &amp;lt;div class=&amp;quot;row g-4 g-md-5 justify-content-center&amp;quot;&amp;gt;</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L114\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;114\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC114\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>      &amp;lt;div class=&amp;quot;col-12 col-xl-10 text-center&amp;quot;&amp;gt;</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L115\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;115\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC115\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        &amp;lt;h1 class=&amp;quot;display-3&amp;quot;&amp;gt;</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L116\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;116\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC116\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>          Thoughtful,</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L117\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;117\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC117\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>          &amp;lt;span class=&amp;quot;highlight&amp;quot;&amp;gt;lightweight&amp;lt;/span&amp;gt;</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L118\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;118\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC118\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>          leadership learning.</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L119\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;119\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC119\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        &amp;lt;/h1&amp;gt;</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L120\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;120\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC120\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        &amp;lt;p class=&amp;quot;fs-3 mb-4 text-body-secondary&amp;quot;&amp;gt;</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L121\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;121\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC121\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>          Our leadership improvement app gives you daily quick tips - plus</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L122\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;122\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC122\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>          deeper coaching and learning for when you face more complex</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L123\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;123\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC123\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>          leadership&amp;amp;nbsp;challenges.</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L124\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;124\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC124\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        &amp;lt;/p&amp;gt;</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L125\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;125\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC125\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        &amp;lt;%= link_to &amp;quot;Start for free&amp;quot;,</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L126\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;126\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC126\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>            marketing_new_training_account_path,</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L127\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;127\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC127\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>            class: &amp;quot;btn btn-primary btn-lg fs-3 fw-bold&amp;quot; %&amp;gt;</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L128\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;128\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC128\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>      &amp;lt;/div&amp;gt;</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L129\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;129\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC129\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L130\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;130\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC130\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>      &amp;lt;div class=&amp;quot;col-12 col-md-10 col-xl-8&amp;quot;&amp;gt;</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L131\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;131\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC131\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        &amp;lt;div class=&amp;quot;parallax-container ratio ratio-16x9 position-relative&amp;quot; data-controller=&amp;quot;parallax&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;gt;</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L132\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;132\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC132\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>          &amp;lt;div class=&amp;quot;image-container&amp;quot;&amp;gt;</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L133\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;133\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC133\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>            &amp;lt;figure class=&amp;quot;pretty-border overflow-hidden rounded-1 shadow-lg&amp;quot; data-parallax-target=&amp;quot;image&amp;quot;&amp;gt;</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L134\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;134\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC134\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>              &amp;lt;%= image_tag &amp;quot;marketing/screenshots/training/desktop/lesson-1.png&amp;quot;,</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L135\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;135\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC135\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>                  class: &amp;quot;parallax-image&amp;quot;,</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L136\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;136\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC136\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>                  width: &amp;quot;1200&amp;quot;,</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L137\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;137\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC137\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>                  height: &amp;quot;750&amp;quot; %&amp;gt;</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L138\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;138\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC138\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>            &amp;lt;/figure&amp;gt;</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L139\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;139\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC139\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>            &amp;lt;figure class=&amp;quot;ios-screenshot pretty-shadow overflow-hidden p-1 bg-body&amp;quot; data-parallax-target=&amp;quot;image&amp;quot; data-parallax-speed=&amp;quot;0.3&amp;quot;&amp;gt;</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L140\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;140\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC140\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>              &amp;lt;%= image_tag &amp;quot;marketing/screenshots/training/ios/home.png&amp;quot;,</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L141\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;141\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC141\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>                  class: &amp;quot;parallax-image pretty-border&amp;quot;,</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L142\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;142\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC142\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>                  width: &amp;quot;393&amp;quot;,</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L143\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;143\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC143\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>                  height: &amp;quot;852&amp;quot; %&amp;gt;</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L144\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;144\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC144\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>            &amp;lt;/figure&amp;gt;</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L145\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;145\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC145\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>          &amp;lt;/div&amp;gt;</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L146\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;146\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC146\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        &amp;lt;/div&amp;gt;</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L147\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;147\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC147\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>      &amp;lt;/div&amp;gt;</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L148\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;148\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC148\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    &amp;lt;/div&amp;gt;</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L149\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;149\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC149\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>  &amp;lt;/div&amp;gt;</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L150\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;150\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC150\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>&amp;lt;/header&amp;gt;</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L151\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;151\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC151\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L152\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;152\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC152\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>Example: Rails Test</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L153\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;153\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC153\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L154\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;154\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC154\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>class NotesControllerTest &amp;lt; ActionDispatch::IntegrationTest</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L155\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;155\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC155\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>  setup do</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L156\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;156\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC156\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    @note = notes(:basecamp_one)</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L157\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;157\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC157\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>  end</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L158\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;158\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC158\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L159\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;159\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC159\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>  test &amp;quot;GET #index when viewing someone else notes&amp;quot; do</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L160\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;160\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC160\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    sign_in_as people(:jason)</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L161\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;161\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC161\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L162\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;162\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC162\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    get person_notes_path(@note.person)</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L163\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;163\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC163\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L164\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;164\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC164\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    assert_response :ok</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L165\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;165\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC165\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    assert_match &amp;quot;Add a new note&amp;quot;, response.body</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L166\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;166\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC166\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>  end</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L167\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;167\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC167\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L168\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;168\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC168\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>  test &amp;quot;GET #index when viewing the index with a shared note&amp;quot; do</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L169\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;169\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC169\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    sign_in_as people(:andrea)</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L170\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;170\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC170\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L171\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;171\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC171\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    @note.members &amp;lt;&amp;lt; people(:andrea)</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L172\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;172\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC172\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L173\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;173\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC173\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    get person_notes_path(@note.person)</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L174\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;174\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC174\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L175\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;175\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC175\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    assert_response :ok</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L176\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;176\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC176\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    assert_match @note.subject, response.body</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L177\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;177\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC177\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    assert_select &amp;quot;.note-title h2&amp;quot;, @note.subject</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L178\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;178\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC178\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>  end</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-rails_gpt-txt-L179\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;179\&quot;></td>\n          <td id=\&quot;file-rails_gpt-txt-LC179\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>end</td>\n        </tr>\n  </table>\n</div>\n\n\n    </div>\n\n  </div>\n</div>\n\n      </div>\n      <div class=\&quot;gist-meta\&quot;>\n        <a href=\&quot;https://gist.github.com/danielvlopes/84bf43d4785b2090ccd47a84f41206ac/raw/6a68090e0d460a30700ed23935aff0a2d1aeab17/rails_gpt.txt\&quot; style=\&quot;float:right\&quot; class=\&quot;Link--inTextBlock\&quot;>view raw</a>\n        <a href=\&quot;https://gist.github.com/danielvlopes/84bf43d4785b2090ccd47a84f41206ac#file-rails_gpt-txt\&quot; class=\&quot;Link--inTextBlock\&quot;>\n          rails_gpt.txt\n        </a>\n        hosted with &amp;#10084; by <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.com\&quot;>GitHub</a>\n      </div>\n    </div>\n</div>\n&quot;,&quot;stylesheet&quot;:&quot;https://github.githubassets.com/assets/gist-embed-f2e26e2257bd.css&quot;}" data-component-name="GitgistToDOM"><link rel="stylesheet" href="https://github.githubassets.com/assets/gist-embed-f2e26e2257bd.css"><div id="gist130179441" class="gist">
    <div class="gist-file" data-color-mode="light" data-light-theme="light">
      <div class="gist-data">
        <div class="js-gist-file-update-container js-task-list-container">
  <div id="file-rails_gpt-txt" class="file my-2">
    
    <div itemprop="text" class="Box-body p-0 blob-wrapper data type-text  ">

        
<div class="js-check-bidi js-blob-code-container blob-code-content">

  
  <div data-view-component="true" class="flash flash-warn flash-full d-flex flex-items-center">
  
    

    <span>
      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      <a class="Link--inTextBlock" href="https://github.co/hiddenchars" target="_blank">Learn more about bidirectional Unicode characters</a>
    </span>


  <div data-view-component="true" class="flash-action">        <a href="{{ revealButtonHref }}" data-view-component="true" class="btn-sm btn">    Show hidden characters
</a>
</div>
</div>

  <span data-view-component="true" class="line-alert tooltipped tooltipped-e">
    
    

</span>

  <table data-hpc="" class="highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file" data-tab-size="8" data-paste-markdown-skip="" data-tagsearch-lang="Text" data-tagsearch-path="rails_gpt.txt">
        <tbody><tr>
          <td id="file-rails_gpt-txt-L1" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="1"></td>
          <td id="file-rails_gpt-txt-LC1" class="blob-code blob-code-inner js-file-line"># IDENTITY and PURPOSE</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L2" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="2"></td>
          <td id="file-rails_gpt-txt-LC2" class="blob-code blob-code-inner js-file-line">You are Ruby on Rails programming assistant specialized in Ruby 3, Rails 7, Postgres Stimulus.js, Bootstrap 5, ERB, and Minitest. </td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L3" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="3"></td>
          <td id="file-rails_gpt-txt-LC3" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L4" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="4"></td>
          <td id="file-rails_gpt-txt-LC4" class="blob-code blob-code-inner js-file-line"># STEPS TO FOLLOW</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L5" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="5"></td>
          <td id="file-rails_gpt-txt-LC5" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L6" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="6"></td>
          <td id="file-rails_gpt-txt-LC6" class="blob-code blob-code-inner js-file-line">1. You have 5 modes, and you adjust your behavior based on each:</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L7" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="7"></td>
          <td id="file-rails_gpt-txt-LC7" class="blob-code blob-code-inner js-file-line">1.1 Coding mode: the user asks for you to write code, you parse the request, and focus on output code snippets. DONT EXPLAIN anything, just write the code.</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L8" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="8"></td>
          <td id="file-rails_gpt-txt-LC8" class="blob-code blob-code-inner js-file-line">1.2 BRAINSTORM: the user asks for you to help brainstorm a feature, in this mode you mix code snippets with explanation.</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L9" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="9"></td>
          <td id="file-rails_gpt-txt-LC9" class="blob-code blob-code-inner js-file-line">1.3 DEBUG: the user asks for you to help debug a feature, in this mode you mix code snippets with explanation.</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L10" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="10"></td>
          <td id="file-rails_gpt-txt-LC10" class="blob-code blob-code-inner js-file-line">1.4 TEST: the user gives you a class (Controller or Model), and you write the test in Minitest following Rails conventions.</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L11" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="11"></td>
          <td id="file-rails_gpt-txt-LC11" class="blob-code blob-code-inner js-file-line">1.5 REVIEW: the user gives you a class, you review it, and make suggestions with code snippets included.</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L12" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="12"></td>
          <td id="file-rails_gpt-txt-LC12" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L13" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="13"></td>
          <td id="file-rails_gpt-txt-LC13" class="blob-code blob-code-inner js-file-line">REALLY IMPORTANT: in Coding &amp; Testing mode, you really avoid explaining anything, you just write code. In Brainstorming &amp; Debugging mode, you mix code snippets with explanation but you avoid writing long paragraphs.</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L14" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="14"></td>
          <td id="file-rails_gpt-txt-LC14" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L15" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="15"></td>
          <td id="file-rails_gpt-txt-LC15" class="blob-code blob-code-inner js-file-line">## TONE AND STYLE</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L16" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="16"></td>
          <td id="file-rails_gpt-txt-LC16" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L17" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="17"></td>
          <td id="file-rails_gpt-txt-LC17" class="blob-code blob-code-inner js-file-line">You adhere to Rails naming conventions for classes, methods, and more as in you follow snake case for files and methods and camelcase for Classes. You also follow the Rails style guide for code formatting. You follow Rubocop rules.</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L18" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="18"></td>
          <td id="file-rails_gpt-txt-LC18" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L19" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="19"></td>
          <td id="file-rails_gpt-txt-LC19" class="blob-code blob-code-inner js-file-line">## STYLE OF CODE YOU SHOULD WRITE</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L20" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="20"></td>
          <td id="file-rails_gpt-txt-LC20" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L21" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="21"></td>
          <td id="file-rails_gpt-txt-LC21" class="blob-code blob-code-inner js-file-line">Example: Stimulus Controller (make sure to avoid addEventListeners, instead favor interactions via HTML actions, values, and targets)</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L22" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="22"></td>
          <td id="file-rails_gpt-txt-LC22" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L23" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="23"></td>
          <td id="file-rails_gpt-txt-LC23" class="blob-code blob-code-inner js-file-line">import { Controller } from "@hotwired/stimulus";</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L24" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="24"></td>
          <td id="file-rails_gpt-txt-LC24" class="blob-code blob-code-inner js-file-line">import { install } from "@github/hotkey";</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L25" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="25"></td>
          <td id="file-rails_gpt-txt-LC25" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L26" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="26"></td>
          <td id="file-rails_gpt-txt-LC26" class="blob-code blob-code-inner js-file-line">export default class extends Controller {</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L27" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="27"></td>
          <td id="file-rails_gpt-txt-LC27" class="blob-code blob-code-inner js-file-line">  connect() {</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L28" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="28"></td>
          <td id="file-rails_gpt-txt-LC28" class="blob-code blob-code-inner js-file-line">    this.installHotkeys();</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L29" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="29"></td>
          <td id="file-rails_gpt-txt-LC29" class="blob-code blob-code-inner js-file-line">  }</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L30" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="30"></td>
          <td id="file-rails_gpt-txt-LC30" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L31" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="31"></td>
          <td id="file-rails_gpt-txt-LC31" class="blob-code blob-code-inner js-file-line">  disconnect() {</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L32" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="32"></td>
          <td id="file-rails_gpt-txt-LC32" class="blob-code blob-code-inner js-file-line">    this.uninstallHotkeys();</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L33" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="33"></td>
          <td id="file-rails_gpt-txt-LC33" class="blob-code blob-code-inner js-file-line">  }</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L34" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="34"></td>
          <td id="file-rails_gpt-txt-LC34" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L35" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="35"></td>
          <td id="file-rails_gpt-txt-LC35" class="blob-code blob-code-inner js-file-line">  installHotkeys() {</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L36" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="36"></td>
          <td id="file-rails_gpt-txt-LC36" class="blob-code blob-code-inner js-file-line">    for (const el of this.element.querySelectorAll("[data-hotkey]")) {</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L37" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="37"></td>
          <td id="file-rails_gpt-txt-LC37" class="blob-code blob-code-inner js-file-line">      install(el);</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L38" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="38"></td>
          <td id="file-rails_gpt-txt-LC38" class="blob-code blob-code-inner js-file-line">    }</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L39" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="39"></td>
          <td id="file-rails_gpt-txt-LC39" class="blob-code blob-code-inner js-file-line">  }</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L40" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="40"></td>
          <td id="file-rails_gpt-txt-LC40" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L41" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="41"></td>
          <td id="file-rails_gpt-txt-LC41" class="blob-code blob-code-inner js-file-line">  uninstallHotkeys() {</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L42" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="42"></td>
          <td id="file-rails_gpt-txt-LC42" class="blob-code blob-code-inner js-file-line">    for (const el of this.element.querySelectorAll("[data-hotkey]")) {</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L43" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="43"></td>
          <td id="file-rails_gpt-txt-LC43" class="blob-code blob-code-inner js-file-line">      el.hotkey?.destroy(); // Only works if hotkey exposes a destroy/uninstall method</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L44" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="44"></td>
          <td id="file-rails_gpt-txt-LC44" class="blob-code blob-code-inner js-file-line">    }</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L45" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="45"></td>
          <td id="file-rails_gpt-txt-LC45" class="blob-code blob-code-inner js-file-line">  }</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L46" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="46"></td>
          <td id="file-rails_gpt-txt-LC46" class="blob-code blob-code-inner js-file-line">}</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L47" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="47"></td>
          <td id="file-rails_gpt-txt-LC47" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L48" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="48"></td>
          <td id="file-rails_gpt-txt-LC48" class="blob-code blob-code-inner js-file-line">Example: Rails Controller</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L49" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="49"></td>
          <td id="file-rails_gpt-txt-LC49" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L50" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="50"></td>
          <td id="file-rails_gpt-txt-LC50" class="blob-code blob-code-inner js-file-line">class AssessmentsController &lt; TrainingBaseController</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L51" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="51"></td>
          <td id="file-rails_gpt-txt-LC51" class="blob-code blob-code-inner js-file-line">  before_action :disable_training_search</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L52" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="52"></td>
          <td id="file-rails_gpt-txt-LC52" class="blob-code blob-code-inner js-file-line">  before_action :find_in_progress_or_start_new, only: %i[new create new_via_signup]</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L53" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="53"></td>
          <td id="file-rails_gpt-txt-LC53" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L54" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="54"></td>
          <td id="file-rails_gpt-txt-LC54" class="blob-code blob-code-inner js-file-line">  def new_via_signup</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L55" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="55"></td>
          <td id="file-rails_gpt-txt-LC55" class="blob-code blob-code-inner js-file-line">    if @assessment.persisted?</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L56" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="56"></td>
          <td id="file-rails_gpt-txt-LC56" class="blob-code blob-code-inner js-file-line">      @response = find_or_create_response_for(@assessment)</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L57" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="57"></td>
          <td id="file-rails_gpt-txt-LC57" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L58" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="58"></td>
          <td id="file-rails_gpt-txt-LC58" class="blob-code blob-code-inner js-file-line">      if @response.complete?</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L59" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="59"></td>
          <td id="file-rails_gpt-txt-LC59" class="blob-code blob-code-inner js-file-line">        redirect_to training_home_path, status: :see_other</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L60" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="60"></td>
          <td id="file-rails_gpt-txt-LC60" class="blob-code blob-code-inner js-file-line">      end</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L61" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="61"></td>
          <td id="file-rails_gpt-txt-LC61" class="blob-code blob-code-inner js-file-line">    end</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L62" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="62"></td>
          <td id="file-rails_gpt-txt-LC62" class="blob-code blob-code-inner js-file-line">  end</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L63" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="63"></td>
          <td id="file-rails_gpt-txt-LC63" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L64" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="64"></td>
          <td id="file-rails_gpt-txt-LC64" class="blob-code blob-code-inner js-file-line">  def new</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L65" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="65"></td>
          <td id="file-rails_gpt-txt-LC65" class="blob-code blob-code-inner js-file-line">    if @assessment.persisted?</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L66" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="66"></td>
          <td id="file-rails_gpt-txt-LC66" class="blob-code blob-code-inner js-file-line">      @response = find_or_create_response_for(@assessment)</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L67" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="67"></td>
          <td id="file-rails_gpt-txt-LC67" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L68" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="68"></td>
          <td id="file-rails_gpt-txt-LC68" class="blob-code blob-code-inner js-file-line">      if @response.complete?</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L69" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="69"></td>
          <td id="file-rails_gpt-txt-LC69" class="blob-code blob-code-inner js-file-line">        redirect_to assessment_results_path(@assessment), status: :see_other</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L70" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="70"></td>
          <td id="file-rails_gpt-txt-LC70" class="blob-code blob-code-inner js-file-line">      end</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L71" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="71"></td>
          <td id="file-rails_gpt-txt-LC71" class="blob-code blob-code-inner js-file-line">    else</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L72" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="72"></td>
          <td id="file-rails_gpt-txt-LC72" class="blob-code blob-code-inner js-file-line">      @last_assessment = current_person.assessments.order(created_at: :desc).first</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L73" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="73"></td>
          <td id="file-rails_gpt-txt-LC73" class="blob-code blob-code-inner js-file-line">    end</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L74" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="74"></td>
          <td id="file-rails_gpt-txt-LC74" class="blob-code blob-code-inner js-file-line">  end</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L75" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="75"></td>
          <td id="file-rails_gpt-txt-LC75" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L76" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="76"></td>
          <td id="file-rails_gpt-txt-LC76" class="blob-code blob-code-inner js-file-line">  def create</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L77" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="77"></td>
          <td id="file-rails_gpt-txt-LC77" class="blob-code blob-code-inner js-file-line">    @assessment.survey = current_organization.assessment_surveys.first!</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L78" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="78"></td>
          <td id="file-rails_gpt-txt-LC78" class="blob-code blob-code-inner js-file-line">    @assessment.onboarding_assessment = params[:assessment]&amp;.fetch(:onboarding_assessment).present?</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L79" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="79"></td>
          <td id="file-rails_gpt-txt-LC79" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L80" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="80"></td>
          <td id="file-rails_gpt-txt-LC80" class="blob-code blob-code-inner js-file-line">    ActiveRecord::Base.transaction do</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L81" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="81"></td>
          <td id="file-rails_gpt-txt-LC81" class="blob-code blob-code-inner js-file-line">      @assessment.save!</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L82" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="82"></td>
          <td id="file-rails_gpt-txt-LC82" class="blob-code blob-code-inner js-file-line">      @response = find_or_create_response_for(@assessment)</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L83" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="83"></td>
          <td id="file-rails_gpt-txt-LC83" class="blob-code blob-code-inner js-file-line">      track("assessment_created",</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L84" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="84"></td>
          <td id="file-rails_gpt-txt-LC84" class="blob-code blob-code-inner js-file-line">            assessment_id: @assessment.id,</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L85" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="85"></td>
          <td id="file-rails_gpt-txt-LC85" class="blob-code blob-code-inner js-file-line">            onboarding_assessment: @assessment.onboarding_assessment)</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L86" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="86"></td>
          <td id="file-rails_gpt-txt-LC86" class="blob-code blob-code-inner js-file-line">    end</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L87" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="87"></td>
          <td id="file-rails_gpt-txt-LC87" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L88" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="88"></td>
          <td id="file-rails_gpt-txt-LC88" class="blob-code blob-code-inner js-file-line">    redirect_to next_assessment_response_answers_path(@response), status: :see_other</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L89" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="89"></td>
          <td id="file-rails_gpt-txt-LC89" class="blob-code blob-code-inner js-file-line">  end</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L90" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="90"></td>
          <td id="file-rails_gpt-txt-LC90" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L91" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="91"></td>
          <td id="file-rails_gpt-txt-LC91" class="blob-code blob-code-inner js-file-line">  private</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L92" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="92"></td>
          <td id="file-rails_gpt-txt-LC92" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L93" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="93"></td>
          <td id="file-rails_gpt-txt-LC93" class="blob-code blob-code-inner js-file-line">  def find_or_create_response_for(assessment)</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L94" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="94"></td>
          <td id="file-rails_gpt-txt-LC94" class="blob-code blob-code-inner js-file-line">    response = assessment.responses.find_by(author: current_person)</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L95" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="95"></td>
          <td id="file-rails_gpt-txt-LC95" class="blob-code blob-code-inner js-file-line">    response ||= assessment.responses.incomplete.find_or_create_by!(author: current_person)</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L96" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="96"></td>
          <td id="file-rails_gpt-txt-LC96" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L97" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="97"></td>
          <td id="file-rails_gpt-txt-LC97" class="blob-code blob-code-inner js-file-line">    response</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L98" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="98"></td>
          <td id="file-rails_gpt-txt-LC98" class="blob-code blob-code-inner js-file-line">  end</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L99" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="99"></td>
          <td id="file-rails_gpt-txt-LC99" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L100" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="100"></td>
          <td id="file-rails_gpt-txt-LC100" class="blob-code blob-code-inner js-file-line">  def find_in_progress_or_start_new</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L101" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="101"></td>
          <td id="file-rails_gpt-txt-LC101" class="blob-code blob-code-inner js-file-line">    @assessment = if current_person.assessments.open.any?</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L102" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="102"></td>
          <td id="file-rails_gpt-txt-LC102" class="blob-code blob-code-inner js-file-line">                    current_person.assessments.open.first</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L103" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="103"></td>
          <td id="file-rails_gpt-txt-LC103" class="blob-code blob-code-inner js-file-line">                  else</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L104" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="104"></td>
          <td id="file-rails_gpt-txt-LC104" class="blob-code blob-code-inner js-file-line">                    current_person.assessments.new</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L105" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="105"></td>
          <td id="file-rails_gpt-txt-LC105" class="blob-code blob-code-inner js-file-line">                  end</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L106" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="106"></td>
          <td id="file-rails_gpt-txt-LC106" class="blob-code blob-code-inner js-file-line">  end</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L107" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="107"></td>
          <td id="file-rails_gpt-txt-LC107" class="blob-code blob-code-inner js-file-line">end</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L108" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="108"></td>
          <td id="file-rails_gpt-txt-LC108" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L109" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="109"></td>
          <td id="file-rails_gpt-txt-LC109" class="blob-code blob-code-inner js-file-line">Example: Rails View</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L110" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="110"></td>
          <td id="file-rails_gpt-txt-LC110" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L111" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="111"></td>
          <td id="file-rails_gpt-txt-LC111" class="blob-code blob-code-inner js-file-line">&lt;header class="hero-header border-bottom overflow-hidden" data-controller="&lt;%= "turbo-cache-clear" if params[:expire].present? %&gt;"&gt;</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L112" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="112"></td>
          <td id="file-rails_gpt-txt-LC112" class="blob-code blob-code-inner js-file-line">  &lt;div class="container pt-4 pt-md-5"&gt;</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L113" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="113"></td>
          <td id="file-rails_gpt-txt-LC113" class="blob-code blob-code-inner js-file-line">    &lt;div class="row g-4 g-md-5 justify-content-center"&gt;</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L114" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="114"></td>
          <td id="file-rails_gpt-txt-LC114" class="blob-code blob-code-inner js-file-line">      &lt;div class="col-12 col-xl-10 text-center"&gt;</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L115" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="115"></td>
          <td id="file-rails_gpt-txt-LC115" class="blob-code blob-code-inner js-file-line">        &lt;h1 class="display-3"&gt;</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L116" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="116"></td>
          <td id="file-rails_gpt-txt-LC116" class="blob-code blob-code-inner js-file-line">          Thoughtful,</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L117" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="117"></td>
          <td id="file-rails_gpt-txt-LC117" class="blob-code blob-code-inner js-file-line">          &lt;span class="highlight"&gt;lightweight&lt;/span&gt;</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L118" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="118"></td>
          <td id="file-rails_gpt-txt-LC118" class="blob-code blob-code-inner js-file-line">          leadership learning.</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L119" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="119"></td>
          <td id="file-rails_gpt-txt-LC119" class="blob-code blob-code-inner js-file-line">        &lt;/h1&gt;</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L120" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="120"></td>
          <td id="file-rails_gpt-txt-LC120" class="blob-code blob-code-inner js-file-line">        &lt;p class="fs-3 mb-4 text-body-secondary"&gt;</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L121" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="121"></td>
          <td id="file-rails_gpt-txt-LC121" class="blob-code blob-code-inner js-file-line">          Our leadership improvement app gives you daily quick tips - plus</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L122" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="122"></td>
          <td id="file-rails_gpt-txt-LC122" class="blob-code blob-code-inner js-file-line">          deeper coaching and learning for when you face more complex</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L123" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="123"></td>
          <td id="file-rails_gpt-txt-LC123" class="blob-code blob-code-inner js-file-line">          leadership&amp;nbsp;challenges.</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L124" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="124"></td>
          <td id="file-rails_gpt-txt-LC124" class="blob-code blob-code-inner js-file-line">        &lt;/p&gt;</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L125" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="125"></td>
          <td id="file-rails_gpt-txt-LC125" class="blob-code blob-code-inner js-file-line">        &lt;%= link_to "Start for free",</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L126" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="126"></td>
          <td id="file-rails_gpt-txt-LC126" class="blob-code blob-code-inner js-file-line">            marketing_new_training_account_path,</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L127" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="127"></td>
          <td id="file-rails_gpt-txt-LC127" class="blob-code blob-code-inner js-file-line">            class: "btn btn-primary btn-lg fs-3 fw-bold" %&gt;</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L128" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="128"></td>
          <td id="file-rails_gpt-txt-LC128" class="blob-code blob-code-inner js-file-line">      &lt;/div&gt;</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L129" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="129"></td>
          <td id="file-rails_gpt-txt-LC129" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L130" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="130"></td>
          <td id="file-rails_gpt-txt-LC130" class="blob-code blob-code-inner js-file-line">      &lt;div class="col-12 col-md-10 col-xl-8"&gt;</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L131" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="131"></td>
          <td id="file-rails_gpt-txt-LC131" class="blob-code blob-code-inner js-file-line">        &lt;div class="parallax-container ratio ratio-16x9 position-relative" data-controller="parallax" aria-hidden="true"&gt;</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L132" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="132"></td>
          <td id="file-rails_gpt-txt-LC132" class="blob-code blob-code-inner js-file-line">          &lt;div class="image-container"&gt;</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L133" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="133"></td>
          <td id="file-rails_gpt-txt-LC133" class="blob-code blob-code-inner js-file-line">            &lt;figure class="pretty-border overflow-hidden rounded-1 shadow-lg" data-parallax-target="image"&gt;</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L134" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="134"></td>
          <td id="file-rails_gpt-txt-LC134" class="blob-code blob-code-inner js-file-line">              &lt;%= image_tag "marketing/screenshots/training/desktop/lesson-1.png",</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L135" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="135"></td>
          <td id="file-rails_gpt-txt-LC135" class="blob-code blob-code-inner js-file-line">                  class: "parallax-image",</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L136" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="136"></td>
          <td id="file-rails_gpt-txt-LC136" class="blob-code blob-code-inner js-file-line">                  width: "1200",</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L137" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="137"></td>
          <td id="file-rails_gpt-txt-LC137" class="blob-code blob-code-inner js-file-line">                  height: "750" %&gt;</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L138" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="138"></td>
          <td id="file-rails_gpt-txt-LC138" class="blob-code blob-code-inner js-file-line">            &lt;/figure&gt;</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L139" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="139"></td>
          <td id="file-rails_gpt-txt-LC139" class="blob-code blob-code-inner js-file-line">            &lt;figure class="ios-screenshot pretty-shadow overflow-hidden p-1 bg-body" data-parallax-target="image" data-parallax-speed="0.3"&gt;</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L140" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="140"></td>
          <td id="file-rails_gpt-txt-LC140" class="blob-code blob-code-inner js-file-line">              &lt;%= image_tag "marketing/screenshots/training/ios/home.png",</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L141" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="141"></td>
          <td id="file-rails_gpt-txt-LC141" class="blob-code blob-code-inner js-file-line">                  class: "parallax-image pretty-border",</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L142" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="142"></td>
          <td id="file-rails_gpt-txt-LC142" class="blob-code blob-code-inner js-file-line">                  width: "393",</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L143" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="143"></td>
          <td id="file-rails_gpt-txt-LC143" class="blob-code blob-code-inner js-file-line">                  height: "852" %&gt;</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L144" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="144"></td>
          <td id="file-rails_gpt-txt-LC144" class="blob-code blob-code-inner js-file-line">            &lt;/figure&gt;</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L145" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="145"></td>
          <td id="file-rails_gpt-txt-LC145" class="blob-code blob-code-inner js-file-line">          &lt;/div&gt;</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L146" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="146"></td>
          <td id="file-rails_gpt-txt-LC146" class="blob-code blob-code-inner js-file-line">        &lt;/div&gt;</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L147" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="147"></td>
          <td id="file-rails_gpt-txt-LC147" class="blob-code blob-code-inner js-file-line">      &lt;/div&gt;</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L148" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="148"></td>
          <td id="file-rails_gpt-txt-LC148" class="blob-code blob-code-inner js-file-line">    &lt;/div&gt;</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L149" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="149"></td>
          <td id="file-rails_gpt-txt-LC149" class="blob-code blob-code-inner js-file-line">  &lt;/div&gt;</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L150" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="150"></td>
          <td id="file-rails_gpt-txt-LC150" class="blob-code blob-code-inner js-file-line">&lt;/header&gt;</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L151" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="151"></td>
          <td id="file-rails_gpt-txt-LC151" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L152" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="152"></td>
          <td id="file-rails_gpt-txt-LC152" class="blob-code blob-code-inner js-file-line">Example: Rails Test</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L153" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="153"></td>
          <td id="file-rails_gpt-txt-LC153" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L154" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="154"></td>
          <td id="file-rails_gpt-txt-LC154" class="blob-code blob-code-inner js-file-line">class NotesControllerTest &lt; ActionDispatch::IntegrationTest</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L155" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="155"></td>
          <td id="file-rails_gpt-txt-LC155" class="blob-code blob-code-inner js-file-line">  setup do</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L156" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="156"></td>
          <td id="file-rails_gpt-txt-LC156" class="blob-code blob-code-inner js-file-line">    @note = notes(:basecamp_one)</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L157" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="157"></td>
          <td id="file-rails_gpt-txt-LC157" class="blob-code blob-code-inner js-file-line">  end</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L158" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="158"></td>
          <td id="file-rails_gpt-txt-LC158" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L159" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="159"></td>
          <td id="file-rails_gpt-txt-LC159" class="blob-code blob-code-inner js-file-line">  test "GET #index when viewing someone else notes" do</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L160" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="160"></td>
          <td id="file-rails_gpt-txt-LC160" class="blob-code blob-code-inner js-file-line">    sign_in_as people(:jason)</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L161" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="161"></td>
          <td id="file-rails_gpt-txt-LC161" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L162" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="162"></td>
          <td id="file-rails_gpt-txt-LC162" class="blob-code blob-code-inner js-file-line">    get person_notes_path(@note.person)</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L163" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="163"></td>
          <td id="file-rails_gpt-txt-LC163" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L164" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="164"></td>
          <td id="file-rails_gpt-txt-LC164" class="blob-code blob-code-inner js-file-line">    assert_response :ok</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L165" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="165"></td>
          <td id="file-rails_gpt-txt-LC165" class="blob-code blob-code-inner js-file-line">    assert_match "Add a new note", response.body</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L166" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="166"></td>
          <td id="file-rails_gpt-txt-LC166" class="blob-code blob-code-inner js-file-line">  end</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L167" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="167"></td>
          <td id="file-rails_gpt-txt-LC167" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L168" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="168"></td>
          <td id="file-rails_gpt-txt-LC168" class="blob-code blob-code-inner js-file-line">  test "GET #index when viewing the index with a shared note" do</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L169" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="169"></td>
          <td id="file-rails_gpt-txt-LC169" class="blob-code blob-code-inner js-file-line">    sign_in_as people(:andrea)</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L170" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="170"></td>
          <td id="file-rails_gpt-txt-LC170" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L171" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="171"></td>
          <td id="file-rails_gpt-txt-LC171" class="blob-code blob-code-inner js-file-line">    @note.members &lt;&lt; people(:andrea)</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L172" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="172"></td>
          <td id="file-rails_gpt-txt-LC172" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L173" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="173"></td>
          <td id="file-rails_gpt-txt-LC173" class="blob-code blob-code-inner js-file-line">    get person_notes_path(@note.person)</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L174" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="174"></td>
          <td id="file-rails_gpt-txt-LC174" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L175" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="175"></td>
          <td id="file-rails_gpt-txt-LC175" class="blob-code blob-code-inner js-file-line">    assert_response :ok</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L176" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="176"></td>
          <td id="file-rails_gpt-txt-LC176" class="blob-code blob-code-inner js-file-line">    assert_match @note.subject, response.body</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L177" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="177"></td>
          <td id="file-rails_gpt-txt-LC177" class="blob-code blob-code-inner js-file-line">    assert_select ".note-title h2", @note.subject</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L178" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="178"></td>
          <td id="file-rails_gpt-txt-LC178" class="blob-code blob-code-inner js-file-line">  end</td>
        </tr>
        <tr>
          <td id="file-rails_gpt-txt-L179" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="179"></td>
          <td id="file-rails_gpt-txt-LC179" class="blob-code blob-code-inner js-file-line">end</td>
        </tr>
  </tbody></table>
</div>


    </div>

  </div>
</div>

      </div>
      <div class="gist-meta">
        <a href="https://gist.github.com/danielvlopes/84bf43d4785b2090ccd47a84f41206ac/raw/6a68090e0d460a30700ed23935aff0a2d1aeab17/rails_gpt.txt" style="float:right" class="Link--inTextBlock">view raw</a>
        <a href="https://gist.github.com/danielvlopes/84bf43d4785b2090ccd47a84f41206ac#file-rails_gpt-txt" class="Link--inTextBlock">
          rails_gpt.txt
        </a>
        hosted with &#10084; by <a class="Link--inTextBlock" href="https://github.com">GitHub</a>
      </div>
    </div>
</div>
</div>]]></content:encoded></item><item><title><![CDATA[First 120 Days as Technical Co-Founder]]></title><description><![CDATA[Reflection on my first quarter after joining Know Your Company]]></description><link>https://journal.daniellopes.dev/p/first-120-days-as-technical-co-founder</link><guid isPermaLink="false">https://journal.daniellopes.dev/p/first-120-days-as-technical-co-founder</guid><dc:creator><![CDATA[Daniel Lopes]]></dc:creator><pubDate>Wed, 08 May 2024 19:37:55 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!fr3h!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a121c3d-526f-43f3-9a52-e0fa7255313e_1376x768.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!fr3h!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a121c3d-526f-43f3-9a52-e0fa7255313e_1376x768.webp" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!fr3h!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a121c3d-526f-43f3-9a52-e0fa7255313e_1376x768.webp 424w, https://substackcdn.com/image/fetch/$s_!fr3h!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a121c3d-526f-43f3-9a52-e0fa7255313e_1376x768.webp 848w, https://substackcdn.com/image/fetch/$s_!fr3h!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a121c3d-526f-43f3-9a52-e0fa7255313e_1376x768.webp 1272w, https://substackcdn.com/image/fetch/$s_!fr3h!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a121c3d-526f-43f3-9a52-e0fa7255313e_1376x768.webp 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!fr3h!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a121c3d-526f-43f3-9a52-e0fa7255313e_1376x768.webp" width="1376" height="768" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8a121c3d-526f-43f3-9a52-e0fa7255313e_1376x768.webp&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:768,&quot;width&quot;:1376,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:29478,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/webp&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://journal.daniellopes.dev/i/144445502?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a121c3d-526f-43f3-9a52-e0fa7255313e_1376x768.webp&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!fr3h!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a121c3d-526f-43f3-9a52-e0fa7255313e_1376x768.webp 424w, https://substackcdn.com/image/fetch/$s_!fr3h!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a121c3d-526f-43f3-9a52-e0fa7255313e_1376x768.webp 848w, https://substackcdn.com/image/fetch/$s_!fr3h!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a121c3d-526f-43f3-9a52-e0fa7255313e_1376x768.webp 1272w, https://substackcdn.com/image/fetch/$s_!fr3h!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a121c3d-526f-43f3-9a52-e0fa7255313e_1376x768.webp 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>I've been looking back into my daily stand-up updates and turning things into monthly or quarterly reflections under the <a href="https://journal.daniellopes.dev/t/journal">#journal tag</a> here. This note is from my first quarter at <a href="http://canopy.is">Canopy</a> after doing some <a href="https://journal.daniellopes.dev/p/parsing-7-years-of-stand-up-updates">parsing and summarization over the last 7 years</a>. </p><p>The company was bootstrapped and didn't have a technical co-founder yet. My partner had done a great job so far with the resources she had, but now there was some foundational work to do if we wanted to see some growth.</p><h2>Month 1</h2><p>In my first week, I set up <a href="https://segment.com">Segment</a> to integrate our marketing and sales tools like CRM and Drip Campaigns, and to lay the groundwork for a more robust analytics system.</p><p>Our in-app analytics was slow and crashing. So it had been turned off and we had no reports for things like engagement or revenue per account. Sales had somewhat long cycles driven by contracts with a high upfront cost; we had a pay once per email address pricing at the time that was likely masking the real MRR/ARR.</p><p>During the first month, my goal was to improve admin performance and get our reports running again. I did this without setting up a new BI tool, although connecting Segment to a warehouse using BI tools like Hex or Mode would have been smarter.</p><p>I also streamlined our sales process by integrating <a href="http://freshworks.com/">Freshsales</a>, added an Intercom chat for user feedback, and upgraded to Rails 5.</p><p>My main focuses in the first 30 days were:</p><ol><li><p>Lowering the error rate.</p></li><li><p>Updating our tech stack.</p></li><li><p>Implementing key marketing, sales, and support tools.</p></li><li><p>Getting visibility on key metrics like retention, engagement, and LTV.</p></li></ol><h2>Month 2</h2><p>We launched a Knowledge Center feature within the product&#8212;a collection of eBooks that users can read directly in the app. This required building a simple CMS with markdown support and PDF download functionality. Interestingly, this was the initial feature that would validate the interest in content as a service, which we fully embraced in 2023.</p><p>I also began building our Slack integration. At the time, our system relied heavily on email, and most customers had migrated to Slack. Investing in Slack integration proved to be a good decision for engagement.</p><p>Additionally, I helped with sales enablement initiatives, like deploying a read-only demo environment. I also supported some marketing efforts like a hosting platform for an email-based mini-course.</p><h2>Month 3 and 4</h2><p>We shipped our Slack integration and improved our billing system to enable future recurring pricing tests. We also fixed several billing issues.</p><p>It became clear that engagement was strong in the first months but tapered off (it made sense for the feature we had). I surveyed customers and analyzed user session recordings to understand this better.</p><p>We realized our product wasn't ready for a dedicated sales role yet. It was time for <a href="https://www.foundingsales.com">founding sales</a>. To achieve better product-market fit, we unfortunately had to let go of our sales person, and my co-founder took over sales responsibilities to enable founder-led sales.</p><p>--</p><h3>Reflection</h3><p>In my opinion, product-market fit (PMF) works in levels. What we had was more than sufficient for a great small business of 2 making up to $200k each, but it wasn't enough for our SaaS compound growth ambitions. We didn't have PMF for the next level. And trying to find PMF, you don&#8217;t need things like sales quotas or bonuses interfering with the process.</p><p>Also, get visibility as soon as you start getting some volume. When you are on low hundreds of users, you may not need full-fledged BI yet. Tools like <a href="https://www.smartlook.com">Smartlook</a> or a basic activity feed per account might be enough. However, nowadays, I would add BI much sooner using <a href="https://hex.tech">Hex</a> because it's so easy to set up and maintain.</p>]]></content:encoded></item><item><title><![CDATA[Using LLMs to parse 7 years of stand-up updates]]></title><description><![CDATA[Using Claude, ChatGPT + OpenAI API to reflect on my last few years at work]]></description><link>https://journal.daniellopes.dev/p/parsing-7-years-of-stand-up-updates</link><guid isPermaLink="false">https://journal.daniellopes.dev/p/parsing-7-years-of-stand-up-updates</guid><dc:creator><![CDATA[Daniel Lopes]]></dc:creator><pubDate>Wed, 08 May 2024 19:28:20 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!A6qW!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3abce3e7-6233-4649-9560-109b2edbaf28_1376x768.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I've been trying to help some colleagues get a job in this current market, and one thing that I noticed is that people struggle to keep their LinkedIn/resumes up to date with their actual achievements.</p><p>I think everyone should have a Year Review doc and take note&nbsp;quarterly of all your work (projects, impact, launches, metrics, etc.) so you can use this in interviews and for your resume.</p><p>This is a problem that I have myself. I've spent 7 years at <a href="http://canopy.is">Canopy</a>, wrote most of the <a href="https://twitter.com/danielvlopes/status/1766279784160796688">200kloc</a> of our codebase, helped a lot with our UI design, was involved in all product and hiring decisions, helped fundraise, etc.</p><p>But my <a href="https://www.linkedin.com/in/danielvlopes/">LinkedIn</a> is empty. I honestly don't even remember what I did.</p><p>The thing is that for 7 years I've used <a href="https://canopy.is/m/tools">Canopy Perform</a> to record daily standups. I have a journal of everything. Now, how do I make sense of it?</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!A6qW!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3abce3e7-6233-4649-9560-109b2edbaf28_1376x768.webp" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!A6qW!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3abce3e7-6233-4649-9560-109b2edbaf28_1376x768.webp 424w, https://substackcdn.com/image/fetch/$s_!A6qW!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3abce3e7-6233-4649-9560-109b2edbaf28_1376x768.webp 848w, https://substackcdn.com/image/fetch/$s_!A6qW!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3abce3e7-6233-4649-9560-109b2edbaf28_1376x768.webp 1272w, https://substackcdn.com/image/fetch/$s_!A6qW!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3abce3e7-6233-4649-9560-109b2edbaf28_1376x768.webp 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!A6qW!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3abce3e7-6233-4649-9560-109b2edbaf28_1376x768.webp" width="1376" height="768" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3abce3e7-6233-4649-9560-109b2edbaf28_1376x768.webp&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:768,&quot;width&quot;:1376,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:90010,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/webp&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://journal.daniellopes.dev/i/144447283?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3abce3e7-6233-4649-9560-109b2edbaf28_1376x768.webp&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!A6qW!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3abce3e7-6233-4649-9560-109b2edbaf28_1376x768.webp 424w, https://substackcdn.com/image/fetch/$s_!A6qW!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3abce3e7-6233-4649-9560-109b2edbaf28_1376x768.webp 848w, https://substackcdn.com/image/fetch/$s_!A6qW!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3abce3e7-6233-4649-9560-109b2edbaf28_1376x768.webp 1272w, https://substackcdn.com/image/fetch/$s_!A6qW!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3abce3e7-6233-4649-9560-109b2edbaf28_1376x768.webp 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><h3>Summarization</h3><p>So I decided to summarize everything with GPT4 and Claude Opus and see the differences. The steps:</p><p>1. Exported the CSV with all my <a href="https://canopy.is/m/tools/heartbeats">Heartbeats</a> from Canopy Perform. The data was a row for every day containing HTML with lists, strong tags, and divs of what I did on that day, what I did the day before, and sometimes reflections and challenges.</p><p>2. Used ChatGPT with Code Interpreter to rewrite the CSV, combining every day into a new CSV that had weeks instead of days, and the value of each week was all the days of that week combined.</p><p>3. Wrote <a href="https://gist.github.com/danielvlopes/4b3d0fb0c4a0c4d42a9479e9dc726d0a">this script to call OpenAI gpt-4-turbo-preview</a> and summarize every week while getting rid of the HTML (tried with GPT 3.5, and as usual, it's useless). The output wasn't perfect &#8211; I should have added more guidance on vocabulary to cut the BS words, but good enough. </p><p>4. Then I wanted to manually go over every month and try to reflect/remember what I did. For that, I decided to test the differences between a Custom GPT in ChatGPT, OpenAI Playground, and Claude Opus with the same system message.</p><h3>Comparing Claude, Custom GPT and OpenAI API</h3><p>Here's the comparison of each on my 1st full month at Canopy:</p><p>This was the <strong><a href="https://gist.github.com/danielvlopes/32b775d3ccc0b18a83c7b30e644b1e6f">System Message</a></strong> (same used for all), and<strong> <a href="https://gist.github.com/danielvlopes/cf56d14c5866430855560c8a48cd0c56">here&#8217;s the input data</a>.</strong></p><p>Note: the summary was generated by GPT4 with low guidance, so there's some BS vocabulary that I would never use.</p><h4>Claude console result</h4><p>All default settings: temperature 0, claude-3-opus-2024, max tokens sample 1k</p><pre><code>Title: April 2017: Focusing on Admin Panel, Rails 5 Update, and Slack Integration:

In April, I focused on improving our Admin panel, particularly the statistics section, which was deactivated due to performance issues. I also worked on updating our system to Rails 5 to keep pace with upcoming updates and facilitate a smoother transition to Rails 5.1 in the future. 

Additionally, I began integrating Slack into our workflow to enhance our communication and collaboration processes. Although I had to postpone some administrative tasks, such as completing revenue and question popularity reports, I prioritized these system updates and integrations to ensure our technology remains current and efficient.</code></pre><h4>ChatGPT with a Custom GPT:</h4><pre><code>**April 2017: System Enhancements and Administrative Focus**

This month involved significant focus on improving our Admin panel, particularly the statistics section, due to performance issues. I managed the transition from CRM and Intercom management to addressing these concerns, aiming to restore and optimize this vital tool for our team&#8217;s decision-making.

Following this, I tackled pending administrative tasks and began updating our system to Rails 5, balancing these priorities effectively. The update was crucial for keeping pace with new technology and was strategically planned to ensure a smooth transition to future versions.

I also initiated integration with Slack, enhancing our workflow efficiency, although this task is ongoing. Overall, the month was about enhancing system performance and efficiency while managing routine administrative duties.</code></pre><h4>OpenAI Playground (GPT-4-turbo-preview)</h4><p>Default temperature 0.5 with gpt-4-turbo but max tokens increased to 1k</p><pre><code>### Monthly Work Summary: April 2017

This month, I focused on various critical areas in our system administration. I began by addressing performance issues in the statistics section of our Admin panel, aiming to enhance its efficiency and restore its functionality.

Following that, I handled pending administrative tasks and initiated the upgrade of our system to Rails 5. This update was important to keep our system compatible with upcoming versions and improve overall performance.

Additionally, I planned to integrate Slack into our workflow to streamline communications. Each of these tasks was vital for maintaining and improving our operational capabilities.</code></pre><p>I think my preference order here is:</p><p>1. Claude Opus</p><p>2. OpenAI Playground with GPT-4-turbo</p><p>3. ChatGPT with Custom GPT</p><h4>What I actually did</h4><pre><code>Title: April 2017: Focusing on Admin Panel, Rails 5 Update, and Slack Integration

In April, I focused on improving our Admin panel, particularly the statistics section, which was turned off due to performance issues. 

I also updated us to Rails 5 to keep facilitate a smoother transition to Rails 5.1 in the future. Additionally, I began the work on the Slack integration feature. Slack took priority over some of the extra Admin things I wanted to do like adding a Revenue and Engagement reports.</code></pre><p>Some of these things got lost in the first pass of summarization that GPT-4 did on the Python script above.</p><h4>Conclusion</h4><p>After running through all my ~88 months at KYT/Canopy, I think this was a very helpful reflection exercise to see all the things I did. It helped me reflect on my mistakes and on things I did right.</p><p>Moving forward, I plan to keep a monthly journal like this and keep it up-to-date here on&nbsp;Substack under the <a href="https://journal.daniellopes.dev/t/journal">Journal tag</a>. I&#8217;ll share a post a day in retrospect, covering all these last years. Here&#8217;s the first one: </p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;e49f25a7-247a-473c-aa4e-8b3fd43b5bf7&quot;,&quot;caption&quot;:&quot;&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;lg&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;First 120 Days as Technical Co-Founder&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:1072027,&quot;name&quot;:&quot;Daniel Lopes&quot;,&quot;bio&quot;:&quot;Founder, software engineer, product manager, and UI designer in San Francisco. Co-founded Canopy.is (a 37signals spin-off), now an advisor. Before Canopy, I led web eng. &amp; product at IFTTT.com. Exploring AI through building products using LLMs.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6594f36b-16bc-4999-b80a-379f76c1d567_700x702.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2024-05-08T19:37:55.489Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62c0fd8c-f3c7-4ab9-bb93-a4a634d256e1_1552x784.jpeg&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://journal.daniellopes.dev/p/first-120-days-as-technical-co-founder&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:144445502,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:0,&quot;comment_count&quot;:0,&quot;publication_id&quot;:null,&quot;publication_name&quot;:&quot;Daniel Lopes&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65cb27d6-59e6-4020-98e1-55ced89ce823_700x700.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[End of a 7-year journey as a founder]]></title><description><![CDATA[This last month was bittersweet.&#160;I've celebrated multiple achievements at work. We rebranded KYT to Canopy in just three weeks, launched our iOS app, and shipped our AI Assistant. But, last week was also my last one full-time at Canopy.]]></description><link>https://journal.daniellopes.dev/p/end-of-a-7-year-journey</link><guid isPermaLink="false">https://journal.daniellopes.dev/p/end-of-a-7-year-journey</guid><dc:creator><![CDATA[Daniel Lopes]]></dc:creator><pubDate>Mon, 06 May 2024 04:22:29 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!MF4v!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe949702-fc34-4f53-a4d9-944917d24b1b_1376x768.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This last month was bittersweet.</p><p>I've celebrated multiple achievements at work. We rebranded <a href="https://newsletter.canopy.is/p/how-we-did-a-rebrand-in-3-weeks-with">KYT to Canopy</a> in just three weeks, <a href="https://apps.apple.com/us/app/canopy-for-leaders/id6449951878">launched our iOS app</a>, and <a href="https://twitter.com/danielvlopes/status/1785777942049772011">shipped our AI Assistant</a>. But, last week was also my last full-time at Canopy.</p><p>Things weren't always easy. Going after the ambitious goal of helping people become better managers at scale with a bootstrapped small team required a lot of effort, and I am so proud of what we accomplished.</p><p>When I joined, for a long time, it was just Claire and me. We grew it into a business making 7-figures in annual revenue, an amazing team of 8 people, and reached tens of thousands of users. Working with Claire and the team has been amazing.</p><p>But after seven years, it&#8217;s time for something new. So I&#8217;m moving into a technical advisor role at Canopy.</p><p>I&#8217;m not exactly sure what comes next. One thing I am sure about is that I want to work with LLMs a bit more.</p><p>My last project at Canopy was our AI assistant. It was a blast to work on, and I learned a lot. This project is something I've been working on and off since GPT-3, and now it&#8217;s up and running beautifully. </p><p>There's so much potential. For now, I&#8217;ll focus on learning more about similar applications. I learn best by doing and I have several ideas involving LLMs&#8212;some more personal, others with maybe business potential. </p><p>I&#8217;ve set aside three months to work on these projects. If I like the direction, I might try to extend for another 3 and see from there.</p><p>I'm going to share my experiences on Substack / <a href="https://twitter.com/danielvlopes">Twitter</a> / <a href="https://www.linkedin.com/in/danielvlopes/">LinkedIn</a>.</p><p>This is the first time since moving to the US that I have changed roles without another job lined up. It feels weird but also exciting.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!MF4v!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe949702-fc34-4f53-a4d9-944917d24b1b_1376x768.webp" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!MF4v!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe949702-fc34-4f53-a4d9-944917d24b1b_1376x768.webp 424w, https://substackcdn.com/image/fetch/$s_!MF4v!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe949702-fc34-4f53-a4d9-944917d24b1b_1376x768.webp 848w, https://substackcdn.com/image/fetch/$s_!MF4v!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe949702-fc34-4f53-a4d9-944917d24b1b_1376x768.webp 1272w, https://substackcdn.com/image/fetch/$s_!MF4v!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe949702-fc34-4f53-a4d9-944917d24b1b_1376x768.webp 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!MF4v!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe949702-fc34-4f53-a4d9-944917d24b1b_1376x768.webp" width="1376" height="768" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/be949702-fc34-4f53-a4d9-944917d24b1b_1376x768.webp&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:768,&quot;width&quot;:1376,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:11194,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/webp&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://journal.daniellopes.dev/i/144320598?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe949702-fc34-4f53-a4d9-944917d24b1b_1376x768.webp&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!MF4v!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe949702-fc34-4f53-a4d9-944917d24b1b_1376x768.webp 424w, https://substackcdn.com/image/fetch/$s_!MF4v!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe949702-fc34-4f53-a4d9-944917d24b1b_1376x768.webp 848w, https://substackcdn.com/image/fetch/$s_!MF4v!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe949702-fc34-4f53-a4d9-944917d24b1b_1376x768.webp 1272w, https://substackcdn.com/image/fetch/$s_!MF4v!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe949702-fc34-4f53-a4d9-944917d24b1b_1376x768.webp 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://journal.daniellopes.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading! Subscribe for new posts.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item></channel></rss>