<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Tessa Kriesel</title>
    <description>The latest articles on DEV Community by Tessa Kriesel (@tessak22).</description>
    <link>https://dev.to/tessak22</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F142543%2F391aa73e-bb8f-4e21-b9bf-b69fccad57f1.jpg</url>
      <title>DEV Community: Tessa Kriesel</title>
      <link>https://dev.to/tessak22</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tessak22"/>
    <language>en</language>
    <item>
      <title>How I Grew Signups 71% in 90 Days by Running GTM Like an Engineer</title>
      <dc:creator>Tessa Kriesel</dc:creator>
      <pubDate>Wed, 08 Jul 2026 02:19:55 +0000</pubDate>
      <link>https://dev.to/tessak22/how-i-grew-signups-71-in-90-days-by-running-gtm-like-an-engineer-cpk</link>
      <guid>https://dev.to/tessak22/how-i-grew-signups-71-in-90-days-by-running-gtm-like-an-engineer-cpk</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.unsplash.com%2Fphoto-1551822554-eaef9bf157f3%3Fcrop%3Dentropy%26cs%3Dtinysrgb%26fit%3Dmax%26fm%3Djpg%26ixid%3DM3wxMTc3M3wwfDF8c2VhcmNofDE4fHxzeXN0ZW1zfGVufDB8fHx8MTc4MzQ2OTAzNnww%26ixlib%3Drb-4.1.0%26q%3D80%26w%3D2000" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.unsplash.com%2Fphoto-1551822554-eaef9bf157f3%3Fcrop%3Dentropy%26cs%3Dtinysrgb%26fit%3Dmax%26fm%3Djpg%26ixid%3DM3wxMTc3M3wwfDF8c2VhcmNofDE4fHxzeXN0ZW1zfGVufDB8fHx8MTc4MzQ2OTAzNnww%26ixlib%3Drb-4.1.0%26q%3D80%26w%3D2000" alt="How I Grew Signups 71% in 90 Days by Running GTM Like an Engineer" width="799" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In my first 90 days at &lt;a href="https://tabstack.ai/?utm_source=tessakriesel.com&amp;amp;utm_medium=blog&amp;amp;utm_campaign=90-days-gtm-like-an-engineer" rel="noopener noreferrer"&gt;Tabstack&lt;/a&gt;, signups went up 71%. I didn’t get there by running a pile of campaigns. I got there by building software.&lt;/p&gt;

&lt;p&gt;I market developer tools, and I’ve been writing code since 2006. That combination changes how I work. Where a lot of marketers open a campaign calendar, I open my terminal. I treat go-to-market like an engineering problem: understand the system, build it, ship it, measure it, then make it better.&lt;/p&gt;

&lt;p&gt;Here’s exactly what I did, week by week, and the play you can take from each one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Before Day One: I Built on the Product First
&lt;/h2&gt;

&lt;p&gt;The best decision I made happened before my first day.&lt;/p&gt;

&lt;p&gt;Once I accepted the offer, I built a real product on Tabstack’s API. It’s called Rival, an open-source competitive-intelligence app that tracks everything a competitor does in public: pricing, hiring, product changes, positioning, reviews, GitHub activity, and it runs full cited research on demand, then tells you what actually changed and uses all five of Tabstack’s endpoints.&lt;/p&gt;

&lt;p&gt;I do this kind of thing with every developer product I take on. I want to understand the product I'm marketing. So I built, and ran a full developer-experience audit while I built Rival, logging every rough edge I hit. Developers are the audience. I wanted the developer experience improved before I sent more developers there.&lt;/p&gt;

&lt;p&gt;Rival actually serves multiple purposes. It’s a test surface for the product. It’s a competitive-intelligence tool I use every day. And it’s a distribution play: it’s open source, self-hosting it requires a Tabstack API key, and I had the campaign to get it in front of developers planned before I ever started.&lt;/p&gt;

&lt;p&gt;The play: use the product yourself, at real depth, before you market it. Build something real with it, not a click-through demo, so you understand what you're actually marketing and you catch the gaps early, before your users hit them. If you're not a coder, try Claude code or other coding agents, they're quite good. Your developers will thank you.&lt;/p&gt;

&lt;p&gt;Rival is open source. You can &lt;a href="https://rivaldemo.com/?ref=tessakriesel.com" rel="noopener noreferrer"&gt;try the live demo&lt;/a&gt; or &lt;a href="https://github.com/tessak22/rival?ref=tessakriesel.com" rel="noopener noreferrer"&gt;dig into the code&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Week One: I Stood Up My Systems Before I Ran Any Marketing
&lt;/h2&gt;

&lt;p&gt;I came in already knowing the product and the direction I wanted to take, so I started with systems, not deliverables. I built our GTM Command Center, the hub the whole operation would run on, so a single change to our positioning reaches everything downstream. And I stood up our CRM under a real constraint: at Mozilla, consent is off by default and we collect almost nothing unless the user says yes, so I can’t lean on behavioral tracking to understand who signs up. My CRM works entirely from public data instead, respectful by design. The Mozilla way.&lt;/p&gt;

&lt;p&gt;I'd done this before. I ran a developer GTM agency before Tabstack, so I came in with a playbook, not a blank page. These systems are that playbook, built for Tabstack.&lt;/p&gt;

&lt;p&gt;The play: don’t start with campaigns. Start with the infrastructure that makes every campaign easier to run.&lt;/p&gt;

&lt;h2&gt;
  
  
  Week Two: I Turned the Docs Gap Into a System
&lt;/h2&gt;

&lt;p&gt;When you actually build on a developer product, its problems announce themselves. A setup step fails silently. The docs skip the exact case you just hit. The messaging never quite says what the thing does. We had all of it, and I refuse to send a developer to a bad developer experience, so I fixed ours before I drove anyone to it. Since I’m a team of one, I didn’t rewrite the docs myself. I built a system, trained deeply on Tabstack: a skill for each kind of doc, a knowledge base of the product, review steps that check every claim against the live API, and a pipeline that drafts and opens a pull request for me to approve.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It wrote 45 docs in a single day, across half a dozen pull requests, that needed only light polish.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is how I work: I build a system to solve the problem, then keep improving it as I use it. For a team of one, that's the best way to scale. The one I wrote for docs writes my marketing content now, too.&lt;/p&gt;

&lt;p&gt;The play: never send a developer to a bad developer experience. Marketing only gets a developer to the door. The developer experience decides whether they stay, and developers judge it fast and rarely give it a second look. That makes DX a prerequisite for marketing, not a parallel track. So fix the docs, the messaging, and the setup that fails silently before you drive anyone to them. And fix them with a system, not a one-off, so they hold as the product keeps changing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Week Three: I Did the Strategic Work, Then Placed the Bets
&lt;/h2&gt;

&lt;p&gt;Leadership wanted to put money into marketing earlier than I’m normally ready to make bets on. Early or not, I wasn't going to spend it on a guess. So I started with the questions that actually matter.&lt;/p&gt;

&lt;p&gt;What does this product need to succeed? How do we stand apart from everyone else fetching web data? What pays off this month, what compounds over multiple quarters, and how do I fund both at once?&lt;/p&gt;

&lt;p&gt;The answer was five bets, each one tied to how developers actually find and adopt tools: showing up in the tools they already use, a public schema library where every use case becomes its own discoverable entry point, content built to be found by the AI models developers now ask, brand and marketing execution, and field and community distribution.&lt;/p&gt;

&lt;p&gt;The play: do the strategic work before you spend a dollar. Understand the market, define what you are and how you differ, then make a short list of bets that balance quick wins against longer plays that compound. The best opportunities will make themselves known this way.&lt;/p&gt;

&lt;h2&gt;
  
  
  Week Four: I Launched by Day 24, With the Data Dashboard First
&lt;/h2&gt;

&lt;p&gt;By day 24, we had our first Product Hunt launch live.&lt;/p&gt;

&lt;p&gt;Product Hunt was deliberate, and not for the obvious reason that developers are there. It’s a source the AI models trust, so a launch doubles as training signal for the assistants developers now ask. I also have a track record there, which buys speed. I planned and launched this one in a few days. Early, trusted, and fast to run was exactly the profile I wanted for a first move.&lt;/p&gt;

&lt;p&gt;Two days before it went live, I stood up our first metrics dashboard across the whole developer journey, API usage, activation funnel, time to value, playground to production, so the moment traffic hit I could see what it did, not just that it showed up. Instrument before you ship, or the launch is noise you can’t learn from.&lt;/p&gt;

&lt;p&gt;The play: early on, ship one real growth effort, and choose it by impact. You’ll have a hundred things you could do. The discipline is picking the one that drives the most growth right now and getting it out, while the longer-term work keeps moving in parallel.&lt;/p&gt;

&lt;h2&gt;
  
  
  Weeks Five and Six: I Built an Agent to Scale Myself, Not to Replace Myself
&lt;/h2&gt;

&lt;p&gt;There’s too much for one person to track. Competitors, community, prospects, sponsorships, content, events. So I built a go-to-market agent, on the open-source Hermes framework, to take the repetitive gathering off my plate.&lt;/p&gt;

&lt;p&gt;The agent runs the recurring jobs on a schedule. Daily competitive-intelligence digests. Community listening across Hacker News, Reddit, GitHub, and more. Prospect signals from our CRM. Prospecting batches. Sponsorship research. A social pipeline with &lt;a href="https://mentiondrop.com/?utm_source=tessakriesel.com&amp;amp;utm_medium=blog&amp;amp;utm_campaign=90-days-gtm-like-an-engineer" rel="noopener noreferrer"&gt;MentionDrop&lt;/a&gt;. Event-prep briefs. It commits its reports and pings me.&lt;/p&gt;

&lt;p&gt;Here’s a concrete one. Rival already runs a cron every night, pulling competitor updates and pushing them into the GTM Command Center. The agent picks that up and synthesizes it, so instead of reading raw diffs every morning, I get the read that actually matters.&lt;/p&gt;

&lt;p&gt;The agent gathers and drafts. I read every report, make the call, and do the work. The system makes me faster. It does not replace me. That distinction is the whole reason it works: I get leverage without giving up a single decision.&lt;/p&gt;

&lt;p&gt;The play: use AI to scale yourself. There is always more GTM work than one person can do by hand, so hand the repetitive gathering to an agent and keep your hours for judgment and action. One person can run a full operation this way. The leverage is real, and every decision stays yours.&lt;/p&gt;

&lt;h2&gt;
  
  
  Week Seven: The Machine Started Pumping
&lt;/h2&gt;

&lt;p&gt;This was the inflection point. The daily reports turned on, and the systems started feeding me fresh intelligence every morning instead of me hunting for it.&lt;/p&gt;

&lt;p&gt;Two things made it click. First, I wired the systems together: the agent could now read and write the CRM directly, and the GTM Command Center held the single source of positioning that fed everything else. Second, I built the operating layer that gives all that daily output somewhere to go, a content calendar and backlog, a distribution system, and outreach lists pulled from my own network of thousands of contacts.&lt;/p&gt;

&lt;p&gt;The play: this is where the work starts compounding. Once your systems connect and feed you output, the job flips from setting the machine up to running on what it produces, and every new problem is easier to solve because the system to handle it is already there.&lt;/p&gt;

&lt;h2&gt;
  
  
  Week Eight: I Turned Product Hunt Into an Engine
&lt;/h2&gt;

&lt;p&gt;Our second launch, Web Research, went out about a month after the first. From there they came almost weekly, on purpose. A launch every week is a forcing function, and the amount of work behind a single one is the part people underestimate: the positioning and messaging, the website work itself (product pages designed and built, homepage and navigation updates, the SEO and discoverability layer), a working demo, images and launch cards, a video, the Product Hunt listing and maker comment, forum posts, social, a launch email, and answering every question in the thread on the day. The fixed deadline is what gets all of it out the door, week after week.&lt;/p&gt;

&lt;p&gt;I already knew the whole site needed a rebuild. I didn’t wait for it. I designed and built a focused product page for this launch myself, so we had something strong to land on now, and left the full rebuild for later.&lt;/p&gt;

&lt;p&gt;The play: don’t wait for perfect resourcing to move. Ship a focused page instead of blocking on a full redo, an agency, or a designer, and own your launch surface end to end. Then put yourself on a cadence and let it do the forcing. Nothing gets work out the door like a deadline you committed to.&lt;/p&gt;

&lt;h2&gt;
  
  
  Week Nine: I Rebuilt the Whole Website Presence in a Weekend
&lt;/h2&gt;

&lt;p&gt;I knew from early on the site needed a full facelift. The old homepage was a single page, and it was weak. Developers couldn’t tell what Tabstack did or didn’t do.&lt;/p&gt;

&lt;p&gt;But I didn’t rebuild the whole site first. I did higher-leverage work and waited. When our research page shipped as a one-off landing page with a new design, it set the standard the rest of the site had to meet. So the facelift happened between launches: the product pages, the homepage relaunch, and the search-visibility layer underneath it, llms.txt, per-page structured data, canonicals, a branded 404, a clean sitemap, so the models developers ask can actually find us. Each launch got a stronger surface to land on, and the presence kept improving without ever blocking a launch.&lt;/p&gt;

&lt;p&gt;The play: improve your GTM presence, but sequence it. Recognize the big investment early, then hold off until it’s the highest-leverage move instead of the urgent one. Let one strong page set the design and messaging standard, then roll the rest out between launches, so your presence keeps getting better without ever blocking one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Week Ten: I Reinvested in the Systems &amp;amp; Data
&lt;/h2&gt;

&lt;p&gt;I pulled the whole operation into one terminal workspace with memory, so I start every session already in context instead of re-explaining myself. And I improved the data. With consent off by default and nothing collected unless you allow it, reliable attribution is genuinely hard, so I made it work within that limit, keeping referrer and UTM data through the consent step instead of losing it. A better workspace makes me faster. Fuller data makes every decision better. I do everything in here from ad copy, to email outreach drafts, to building agent skills. It empowers me to do everything within the defined system.&lt;/p&gt;

&lt;p&gt;This is also the week I turned on our first paid spend, a TLDR newsletter placement, and not a day before. I waited until the site and the developer experience were good enough that the traffic would land on something ready.&lt;/p&gt;

&lt;p&gt;The play: reinvest in your own systems and your data as you go. Efficiency and better information both compound. And don’t buy traffic until you’ve built something worth sending it to.&lt;/p&gt;

&lt;h2&gt;
  
  
  Week Eleven: The Systems Started Paying Me Back
&lt;/h2&gt;

&lt;p&gt;By now, running go-to-market like an engineer had a feel to it. Every time I hit a wall, I solved it for good.&lt;/p&gt;

&lt;p&gt;I’d made launch images by hand for three launches, hours each in Claude Design, so I built a helper that renders them on brand in minutes. My next launch’s imagery took me minutes. I planned a ten-category schema library and had the agent build it in a single overnight batch while I reviewed and shipped it in the morning, weeks of work done in hours. And I measured it hard: a four-launch traffic comparison, a growth report going back to April, attribution diagnostics, a case-study shortlist of our most-engaged orgs, and an exec narrative packaged into a deck.&lt;/p&gt;

&lt;p&gt;I’m not doing less. The more my systems handle, the more I get to take on, well beyond what one person could carry alone.&lt;/p&gt;

&lt;p&gt;The play: solve every hurdle once. Feel the pain a couple of times, then build the thing that removes it for good, a tool that turns hours of design work into minutes, an agent that runs an overnight build while you sleep. Each fix makes the next thing easier, and easier is what lets one person do the work of a team. That is what running go-to-market like an engineer actually buys you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Week Twelve: Not Every Launch Is a Tentpole
&lt;/h2&gt;

&lt;p&gt;Our fifth launch, Schema Source, was a quick one. It put eyes on the schema source tool our team built and the schema library of pre-defined schemas my agent built and kept the cadence alive without a heavy lift.&lt;/p&gt;

&lt;p&gt;The rest of the week went to the work that doesn’t announce itself. I integrated a fresh positioning pass so our message stayed sharp as we grew, and I got the Browser Automation launch copy ready for the next week, keeping it strictly to what was actually shipping, because overselling a developer tool costs you the moment someone tries it.&lt;/p&gt;

&lt;p&gt;The play: not every launch has to be a tentpole. A quick, light launch off something you already shipped keeps the cadence alive and puts eyes on an asset, without the heavy lift of a marquee release. The cadence is the engine. Sometimes you just feed it with what you already have.&lt;/p&gt;

&lt;h2&gt;
  
  
  Week Thirteen: Final Push before Day 90
&lt;/h2&gt;

&lt;p&gt;Week thirteen ran hard. The sixth launch, Browser Automation, went out with its announcement email. I shipped a competitor-brief tool, and finished the CRM enrichment layer that turns an email into a cited public profile on Tabstack’s own research endpoint. Even then I kept tuning the systems, because at day 90 I’m still sharpening them.&lt;/p&gt;

&lt;p&gt;Then I measured my own 90 days the same way I measure a launch. Here’s what the systems produced:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Signups up 71%&lt;/li&gt;
&lt;li&gt;Activation up 29%&lt;/li&gt;
&lt;li&gt;API requests up almost 6x&lt;/li&gt;
&lt;li&gt;Website traffic up 129%&lt;/li&gt;
&lt;li&gt;Around 1,096 commits&lt;/li&gt;
&lt;li&gt;29,938 Tabstack API calls of my own, the heaviest usage on the platform&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tabstack is one tool in my stack, but it earns its spot. Rival is built entirely on it. Here’s a small example of why. I wanted to pull a recipe off a page and get clean, structured JSON back for a blog. I asked Claude to just do it, and it failed. Then I had it call Tabstack, and the data came back in seconds, structured exactly the way I needed and exactly what the model couldn’t produce on its own.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Bottom Line
&lt;/h2&gt;

&lt;p&gt;I grew signups 71% in 90 days by building the systems that made me faster. Work smarter, not harder.&lt;/p&gt;

&lt;p&gt;If you market a developer tool, or you’re a developer thinking about marketing your own, here’s the whole thing in one breath. Learn the product by building on it. Fix the developer experience, and build the system that keeps it fixed. Turn launches into a cadence, and never launch without your data ready. Use AI to scale yourself without handing over the judgment. And solve every hurdle once.&lt;/p&gt;

&lt;p&gt;You don’t have to be an engineer to run go-to-market this way. It just helps to think like one. I’m a marketer for developers because I’m a developer, and after 90 days I’m more sure than ever that’s the advantage.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you’re building agents that need to read the live web, Tabstack is worth a look.&lt;/em&gt; &lt;a href="https://tabstack.ai/?ref=tessakriesel.com" rel="noopener noreferrer"&gt;&lt;em&gt;Grab an API key&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Everything I Built and Shipped
&lt;/h2&gt;

&lt;p&gt;If you want the action behind the playbook, here’s the full body of work from the quarter.&lt;/p&gt;

&lt;h3&gt;
  
  
  The systems (the machine everything runs on)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Rival&lt;/strong&gt; : an open-source competitive-intelligence app on all five Tabstack endpoints: multi-surface scanning (homepage, pricing, blog, changelog, reviews, profile), AI-generated diffs, on-demand cited research, a positioning matrix, threat scoring, a public streaming demo, nightly pushes into the GTM Command Center, and its own MCP server. Open-sourced.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GTM Command Center&lt;/strong&gt; : the hub the whole operation runs on: versioned positioning and product context, AI work sessions (strategy, creation, feedback, analysis, optimization), a campaigns module with an AI brief generator, a versioned content and artifact library with SEO/OG and distribution, customer-research ingestion (themes, sentiment, quotes), performance logging that proposes updates back to the context, live metric connectors (PostHog, GA4, EthicalAds), a campaign-performance dashboard, team management, notifications, magic-link auth with domain gating, and an MCP server every other system reads and writes to.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tabstack CRM&lt;/strong&gt; : public-data-only enrichment and ICP scoring, an identity pass (Gravatar, GitHub, npm, PyPI, Slack), a source-linked signal feed, a prospect and account pipeline, funnel-stage imports, and a hosted MCP server. Later moved to Airtable with a trace-based enrichment pipeline.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GTM agent&lt;/strong&gt; : built on the open-source Hermes framework: recurring competitive-intel, community-listening, prospecting, sponsorship, and social jobs, network intelligence, publishing integrations, and a Telegram interface. It gathers and drafts; I decide and act.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tabstack OS&lt;/strong&gt; : one terminal workspace with memory: a state-of-work brain, session briefings, reference-repo sync, and a portable knowledge mirror.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The tech-writing and blog-authoring system&lt;/strong&gt; : a skill per doc type, a product knowledge base, accuracy-checking review agents, and a draft-to-pull-request pipeline.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Skills, subagents, and com &lt;strong&gt;mands I built&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Custom skills: api-docs, tech-writing, changelog, readme-writer, tabstack-sdk, blog-author, external-publication-editor, sdk-sync, quiver-publish, product-marketing, vbf-messaging, competitor-profiling, state-of-work, crm-import, writing-clearly-and-concisely, plus a mirrored marketing-skills pack&lt;/li&gt;
&lt;li&gt;Review subagents: api-reviewer, docs-reviewer, readme-writer&lt;/li&gt;
&lt;li&gt;Slash commands for the doc and publishing workflows&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Marketing website (built and rebuilt)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Four product pages: structured extraction, browser automation, web research, and competitive intelligence, with hero demos and real token-cost visuals&lt;/li&gt;
&lt;li&gt;A full homepage relaunch (dark nav and footer, Stack mega-menu) and a blog redesign&lt;/li&gt;
&lt;li&gt;A Developer Hub / resources overhaul and a Use Cases section&lt;/li&gt;
&lt;li&gt;Attribution plumbing: referral/UTM passthrough into signup CTAs, entry referrer/UTMs retained across the cookie-consent delay, and internal links de-tagged&lt;/li&gt;
&lt;li&gt;Consent-gated web analytics&lt;/li&gt;
&lt;li&gt;AI-search visibility: llms.txt and llms-full.txt, per-page JSON-LD, canonicals, keyword-targeted meta titles, a branded 404, a clean sitemap, and legacy redirects&lt;/li&gt;
&lt;li&gt;A consistent UTM + GA taxonomy across every CTA, an accessibility pass, and a font migration to the Mozilla brand faces&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Docs
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;45 docs in a single day&lt;/li&gt;
&lt;li&gt;The Interactive Mode set (quickstart, guides, launch post) and an accuracy pass&lt;/li&gt;
&lt;li&gt;Per-endpoint API references (extract/json, extract/markdown, generate/json, automate, research)&lt;/li&gt;
&lt;li&gt;Quickstarts (first extraction, interactive mode, research)&lt;/li&gt;
&lt;li&gt;Seven how-to guides (effort levels, geotargeting, schema design, streaming, production reliability, integrations, LangChain)&lt;/li&gt;
&lt;li&gt;A 14-page comparisons section and SDK-first rewrites&lt;/li&gt;
&lt;li&gt;A changelog page covering SDK 2.0.0–2.6.1&lt;/li&gt;
&lt;li&gt;Ongoing docs work from DevRel: error reference, research guide, a generate-vs-extract page, production rate limits, a full docs audit, and single-source changelog data&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Developer tooling
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The Tabstack CLI (built by DevRel, hardened to launch-ready, with a schema-pull command and install script)&lt;/li&gt;
&lt;li&gt;A public vertical schema library, ten categories built in a single overnight batch, plus a competitor-profile schema&lt;/li&gt;
&lt;li&gt;A competitor-brief demo app spanning all five endpoints (an 11-section streaming brief with a two-URL positioning comparison)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Product Hunt launches (six)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Six launches: the first Tabstack launch, then Web Research, Structured Extraction, Dev Tools, Schema Source, and Browser Automation&lt;/li&gt;
&lt;li&gt;For each one: positioning, messaging, taglines, the listing and maker comment, ten forum posts, a launch email, and answering questions in the thread on the day&lt;/li&gt;
&lt;li&gt;A reusable Product Hunt image helper (on-brand launch cards in minutes), launch-day sentiment analysis, and launch-history + launch-comparison research&lt;/li&gt;
&lt;li&gt;Launch videos by DevRel&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  GTM intelligence and reporting
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Daily competitive-intel, community-signal, and CRM-signal reports; weekly competitive summaries, account intelligence, prospecting, sponsorship, social, and events reports&lt;/li&gt;
&lt;li&gt;A four-launch traffic comparison, a growth report since April, attribution diagnostics, an engaged-orgs case-study shortlist with pre-filled briefs, and an exec growth narrative with a slide deck&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Content
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;A dozen technical blog drafts, personal-voice and brand voice profiles, a monthly content calendar, a distribution system, and a 30-post backlog&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Positioning and messaging
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;A five-bet growth investment plan, a VBF messaging framework, six audience micro-segments, a jobs-to-be-done framework, exec and company one-pagers, and a full positioning integration that leans on Mozilla’s trust and privacy stance (ephemeral processing, no training on your data, privacy by default)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Specs and plans
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Design specs and implementation plans for the blog-author system, the Tabstack OS workspace, the using-Tabstack skill, the competitive-intelligence sales page, and the competitor-brief tool&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Analytics and dashboards
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Three PostHog dashboards (GTM Metrics, live Launch Day, and Growth/Attribution/Signups) with 36 insights&lt;/li&gt;
&lt;li&gt;The GTM Command Center’s own campaign-performance dashboard, pulling spend and metrics from PostHog, GA4, and EthicalAds to show cost-per-outcome across every campaign&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Paid and community distribution
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;A TLDR newsletter placement (first paid spend), a bytes.dev newsletter sponsorship, an EthicalAds campaign (per-segment copy and creative), Reddit Ads, and a paid-channel experiment plan&lt;/li&gt;
&lt;li&gt;Creator and sponsorship lists mined from a network of thousands&lt;/li&gt;
&lt;li&gt;An agent-ecosystem play: registered the product as an agent, plus an agent-injection campaign plan&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Team and ops
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Hired and directed our DevRel engineer, Steve McDougall, brought on Flo Merian as our Product Hunt hunter, and onboarded our brand-and-marketing agency, Conversion Factory&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Research and evaluation
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;A pricing evaluation, competitor ad-intelligence research, and a developer-marketing playbook synthesis&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  And the dogfooding receipt
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;27 product issues filed to engineering from real use, and the #1 power user of the Tabstack API at 29,938 calls&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devrel</category>
    </item>
    <item>
      <title>I Stopped Checking My Mentions Dashboard. Now an Agent Drafts the Replies.</title>
      <dc:creator>Tessa Kriesel</dc:creator>
      <pubDate>Tue, 16 Jun 2026 23:06:44 +0000</pubDate>
      <link>https://dev.to/tessak22/i-stopped-checking-my-mentions-dashboard-now-an-agent-drafts-the-replies-49ak</link>
      <guid>https://dev.to/tessak22/i-stopped-checking-my-mentions-dashboard-now-an-agent-drafts-the-replies-49ak</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxcohpdsxjcy30gucxoaa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxcohpdsxjcy30gucxoaa.png" alt="I Stopped Checking My Mentions Dashboard. Now an Agent Drafts the Replies." width="800" height="559"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Every monitoring tool sells you the same thing. A dashboard. You open it, you scroll, you promise yourself you'll keep up. Two weeks later you stop opening it.&lt;/p&gt;

&lt;p&gt;Sound familiar? The dashboard was never the point. The point is the handful of conversations happening right now where you could be useful, and those rot in a browser tab you forgot to check.&lt;/p&gt;

&lt;p&gt;I run GTM for &lt;a href="https://tabstack.ai/?utm_source=tessak22.com&amp;amp;utm_medium=referral&amp;amp;utm_campaign=mentiondrop-mcp-post" rel="noopener noreferrer"&gt;Tabstack&lt;/a&gt;, so this as an actual problem I needed to solve. I need to know when someone mentions us, when someone's frustrated with a tool in our space, when there's a question I can help with. But those few conversations sit buried under hundreds that look relevant and aren't. That's the work: cutting the noise down to what matters, then replying before it goes cold. Neither half scales by adding another tab to your morning.&lt;/p&gt;

&lt;p&gt;So I'd already taken a swing at it. My Hermes GTM agent runs a community signals report every morning before I'm even at my desk. It works. But on its own, it leaned toward housekeeping tasks: which PR merged, which repo pushed overnight. The conversations I actually wanted stayed the thinnest slice of the report, because raw keywords drown them in noise.&lt;/p&gt;

&lt;p&gt;Then MentionDrop shipped an MCP. I wired it into Hermes this week, and the report I re-ran was completely different.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the MCP actually changes
&lt;/h2&gt;

&lt;p&gt;MentionDrop has always done the hard part, filtering social noise into real signal. The MCP changes how you use it. Instead of a dashboard I visit, it becomes a set of tools my agent calls directly: the same filtered data, exposed so Hermes can pull it without me clicking anything.&lt;/p&gt;

&lt;p&gt;That's the whole shift. A tool with an MCP doesn't have to be a place you go. It can be a capability your agent has.&lt;/p&gt;

&lt;p&gt;Connecting it took about two minutes. The tuning came after. A broad keyword pulls in everything at first; one of mine was matching a soccer player, an obituary, and a makeup app. What sold me is how much control MentionDrop hands you to fix that. Every keyword takes a role, a context sentence, a relevance floor, and exclusion terms. A few minutes turned a messy feed into a high-signal one, and because the filter learns from what I mark reviewed, tomorrow's run will be sharper than today's.&lt;/p&gt;

&lt;p&gt;Here's the division of labor I landed on: MentionDrop does the filtering, Hermes pulls what's left into one morning list and drafts a reply for each in my voice. But Hermes can't touch my account or post anything in public. That part is mine. I read the draft, make my edits, and hit post. Every draft also clears my editorial principles before it reaches me, so what I'm reviewing already sounds like me.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I actually get now
&lt;/h2&gt;

&lt;p&gt;A short list each morning. Five or six conversations, not five hundred. Each one comes with a line on why it matters, a direct link, and a reply already drafted the way I'd say it.&lt;/p&gt;

&lt;p&gt;Here's one from today's run. Hermes flagged a developer on r/ClaudeAI stuck trying to install Apify, the kind of friction moment where an alternative is genuinely welcome. It pulled the thread, noted why it mattered, and wrote the draft:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Apify's MCP setup can be pretty finicky, the actor runtime adds a bunch of overhead that doesn't play nicely with Claude's tool calling in every setup.  &lt;/p&gt;

&lt;p&gt;If you're trying to pull structured data or do browser-based research, you might find Tabstack's API simpler to wire up. It's a plain REST API with no runtime to configure. Happy to share a quick example if you tell me what you're trying to extract.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I read it, removed spaces around the em dashes, and hit post. Done in 3o seconds.&lt;/p&gt;

&lt;p&gt;Compare that to what Hermes gave me on its own a few days ago: a thorough rundown of GitHub activity. Which issues got acknowledged, which PR was blocking a launch, which repo pushed overnight. All true, all useful for ops. But not one conversation I could go &lt;em&gt;be useful in&lt;/em&gt;. That report was a status update. This one's a revenue-driving to-do list.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"MentionDrop's MCP turns my Hermes agent's morning report from a status update into a revenue-driving to-do list."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The bottom line
&lt;/h2&gt;

&lt;p&gt;I only set this up this week, so I won't pretend it has remade everything. But the first real run handed me a list worth acting on, and that's the part that has me hooked. The tool didn't change. &lt;a href="https://www.mentiondrop.com/?utm_source=tessakrieselcom&amp;amp;utm_medium=referral&amp;amp;utm_campaign=mentiondrop-mcp-post" rel="noopener noreferrer"&gt;MentionDrop&lt;/a&gt; was already good at the filtering. What changed is that it shipped an MCP, and that turned it from something I check into something my agent runs for me.&lt;/p&gt;

&lt;p&gt;That's what I keep coming back to. My agent was already doing the work. It just needed better inputs. An MCP is how a good tool stops being a destination and becomes a capability.&lt;/p&gt;

</description>
      <category>ai</category>
    </item>
    <item>
      <title>How I Deployed Hermes Agent on Railway with Telegram (And Every Gotcha I Hit Along the Way)</title>
      <dc:creator>Tessa Kriesel</dc:creator>
      <pubDate>Tue, 12 May 2026 21:14:06 +0000</pubDate>
      <link>https://dev.to/tessak22/how-i-deployed-hermes-agent-on-railway-with-telegram-and-every-gotcha-i-hit-along-the-way-4hhk</link>
      <guid>https://dev.to/tessak22/how-i-deployed-hermes-agent-on-railway-with-telegram-and-every-gotcha-i-hit-along-the-way-4hhk</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR for the skimmers
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Hermes is NousResearch's self-improving AI agent framework—persistent memory, skills system, multi-platform messaging, multiple LLM providers&lt;/li&gt;
&lt;li&gt;You can run it as a persistent Docker service on Railway with Telegram as your interface&lt;/li&gt;
&lt;li&gt;The docs don't cover Railway/Docker deployment, so I had to figure most of this out through trial, error, and log-reading&lt;/li&gt;
&lt;li&gt;There are 10 specific gotchas that will wreck your deploy if you don't know about them&lt;/li&gt;
&lt;li&gt;Full working files at the end of this post&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Why I built this
&lt;/h2&gt;

&lt;p&gt;When I found Hermes—NousResearch's self-improving agent framework—I knew I wanted it in the cloud. I didn't want to think about whether my laptop was on. I wanted to message it from my phone at any hour and have it just work.&lt;/p&gt;

&lt;p&gt;The problem? There is essentially zero documentation for deploying Hermes to a persistent cloud service like Railway. The install docs assume you're running it locally. The Docker support exists but isn't documented in any deployment context. And when you're dealing with a gateway-based agent that uses volumes, environment variables, MCP subprocess servers, and Telegram webhooks, the failure surface is enormous.&lt;/p&gt;

&lt;p&gt;This post is the full deployment story—every gotcha, every fix, every file—so you don't have to spend three days in Railway logs the way I did.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Hermes actually is
&lt;/h2&gt;

&lt;p&gt;Before I get into the deployment mechanics, let me quickly explain what Hermes is and why it's worth the deployment friction.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/NousResearch/hermes-agent?ref=tessakriesel.com" rel="noopener noreferrer"&gt;Hermes&lt;/a&gt; is NousResearch's AI agent framework. What makes it different from a simple chatbot or wrapper:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Self-improving skills system&lt;/strong&gt; : Hermes creates skills from experience and improves them over time. You can also load external skill directories.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Persistent memory&lt;/strong&gt; : &lt;code&gt;MEMORY.md&lt;/code&gt; and &lt;code&gt;USER.md&lt;/code&gt; build up across sessions. The agent actually remembers you.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-platform messaging&lt;/strong&gt; : Telegram, Discord, Slack, WhatsApp, Signal, email—you pick your interface.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-LLM support&lt;/strong&gt; : Anthropic, OpenRouter, Nous Portal, and more. You can configure fallback providers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MCP support&lt;/strong&gt; : Connect external tools via Model Context Protocol servers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cron jobs, kanban, session search, hooks&lt;/strong&gt; : Full agentic infrastructure baked in.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Config lives in &lt;code&gt;~/.hermes/&lt;/code&gt;&lt;/strong&gt; : Main files are &lt;code&gt;config.yaml&lt;/code&gt;, &lt;code&gt;.env&lt;/code&gt;, and &lt;code&gt;SOUL.md&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Getting it running on Railway
&lt;/h2&gt;

&lt;p&gt;This section covers only what's Railway-specific. For general Hermes setup—skills, SOUL.md content, memory configuration—refer to the &lt;a href="https://github.com/NousResearch/hermes-agent?ref=tessakriesel.com" rel="noopener noreferrer"&gt;Hermes repo&lt;/a&gt;. What follows is the deployment layer on top of that.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;p&gt;Before you start:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://railway.com/?ref=tessakriesel.com" rel="noopener noreferrer"&gt;Railway account&lt;/a&gt; with the CLI installed (&lt;code&gt;npm install -g @railway/cli&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Railway CLI logged in: &lt;code&gt;railway login&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;A Telegram bot token (create one via &lt;a href="https://t.me/BotFather?ref=tessakriesel.com" rel="noopener noreferrer"&gt;@BotFather&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Your Telegram user ID (message &lt;a href="https://t.me/userinfobot?ref=tessakriesel.com" rel="noopener noreferrer"&gt;@userinfobot&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;An Anthropic API key (or whichever LLM provider you're using)&lt;/li&gt;
&lt;li&gt;Docker installed locally if you want to test the build before deploying&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 1: Create your repo structure
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;your-agent/
├── Dockerfile
├── entrypoint.sh
├── railway.json
├── .env.example
├── .gitignore
├── AGENTS.md # Optional — auto-injected context every session
└── hermes/
    ├── cli-config.yaml
    └── SOUL.md

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;hermes/&lt;/code&gt; directory is your agent's config source. The entrypoint copies these files into the Railway volume on every startup, so changes you commit and deploy take effect immediately.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Create the core files
&lt;/h3&gt;

&lt;p&gt;Create &lt;code&gt;Dockerfile&lt;/code&gt;, &lt;code&gt;entrypoint.sh&lt;/code&gt;, &lt;code&gt;railway.json&lt;/code&gt;, and &lt;code&gt;hermes/cli-config.yaml&lt;/code&gt; using the full working files later in this post. Come back to this step once you've read the gotchas—they'll explain some choices in those files that would otherwise seem arbitrary.&lt;/p&gt;

&lt;p&gt;The one file you'll want to create now is &lt;code&gt;hermes/SOUL.md&lt;/code&gt;. This is your agent's identity—who it is, what it knows, how it behaves. The &lt;a href="https://github.com/NousResearch/hermes-agent?ref=tessakriesel.com" rel="noopener noreferrer"&gt;Hermes repo&lt;/a&gt; covers what goes in SOUL.md. Create it before your first deploy so the agent starts with a defined persona rather than a blank slate.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Set up the Telegram bot
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Message &lt;a href="https://t.me/BotFather?ref=tessakriesel.com" rel="noopener noreferrer"&gt;@BotFather&lt;/a&gt; on Telegram&lt;/li&gt;
&lt;li&gt;Send &lt;code&gt;/newbot&lt;/code&gt; and follow the prompts&lt;/li&gt;
&lt;li&gt;Copy the token it gives you—that's &lt;code&gt;TELEGRAM_BOT_TOKEN&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Message &lt;a href="https://t.me/userinfobot?ref=tessakriesel.com" rel="noopener noreferrer"&gt;@userinfobot&lt;/a&gt; to get your numeric user ID—that's &lt;code&gt;TELEGRAM_ALLOWED_USERS&lt;/code&gt; and &lt;code&gt;TELEGRAM_HOME_CHANNEL&lt;/code&gt; (they're the same value for a personal DM setup)&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Step 4: Initialize the Railway project
&lt;/h3&gt;

&lt;p&gt;From your repo root:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Initialize and link to Railway&lt;/span&gt;
railway init

&lt;span class="c"&gt;# Create the service with an initial deploy&lt;/span&gt;
railway up &lt;span class="nt"&gt;--detach&lt;/span&gt;

&lt;span class="c"&gt;# Link to the service by name&lt;/span&gt;
railway service &lt;span class="s2"&gt;"your-service-name"&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 5: Set environment variables
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;railway variables &lt;span class="nb"&gt;set &lt;/span&gt;&lt;span class="nv"&gt;ANTHROPIC_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;sk-ant-...
railway variables &lt;span class="nb"&gt;set &lt;/span&gt;&lt;span class="nv"&gt;TELEGRAM_BOT_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;...
railway variables &lt;span class="nb"&gt;set &lt;/span&gt;&lt;span class="nv"&gt;TELEGRAM_ALLOWED_USERS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;123456789
railway variables &lt;span class="nb"&gt;set &lt;/span&gt;&lt;span class="nv"&gt;TELEGRAM_HOME_CHANNEL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;123456789
railway variables &lt;span class="nb"&gt;set &lt;/span&gt;&lt;span class="nv"&gt;TELEGRAM_HOME_CHANNEL_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Your Name DM"&lt;/span&gt;
railway variables &lt;span class="nb"&gt;set &lt;/span&gt;&lt;span class="nv"&gt;HERMES_HUMAN_DELAY_MODE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;natural
railway variables &lt;span class="nb"&gt;set &lt;/span&gt;&lt;span class="nv"&gt;HERMES_ACCEPT_HOOKS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add any additional secrets for MCP servers you're connecting:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;railway variables &lt;span class="nb"&gt;set &lt;/span&gt;&lt;span class="nv"&gt;NOTION_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;...
railway variables &lt;span class="nb"&gt;set &lt;/span&gt;&lt;span class="nv"&gt;NOUS_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;... &lt;span class="c"&gt;# if using Nous Portal fallback&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 6: Add the persistent volume
&lt;/h3&gt;

&lt;p&gt;This is the most important step and the order matters—add the volume before your first real deploy.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;railway volume add &lt;span class="nt"&gt;--mount-path&lt;/span&gt; /root/.hermes

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The volume must be mounted at &lt;code&gt;/root/.hermes&lt;/code&gt;—the entire Hermes home directory, not a subdirectory. See Gotcha 2 for why this matters.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 7: Redeploy and verify
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;railway up &lt;span class="nt"&gt;--detach&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Watch the build logs in the Railway dashboard. A successful startup looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Hermes config ready. Starting gateway...
⚕ Hermes Gateway Starting...
Messaging platforms + cron scheduler

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you see the gateway banner, send a message to your Telegram bot. It should respond.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 8: Set up auto-deploy on push
&lt;/h3&gt;

&lt;p&gt;Railway doesn't automatically redeploy when you push to GitHub unless you connect the repo through their UI. The easiest workaround is a git post-push hook:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create the hook&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; .git/hooks/post-push &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;'
#!/bin/bash
echo "Deploying to Railway..."
railway up --detach
&lt;/span&gt;&lt;span class="no"&gt;EOF

&lt;/span&gt;&lt;span class="nb"&gt;chmod&lt;/span&gt; +x .git/hooks/post-push

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now &lt;code&gt;git push&lt;/code&gt; triggers a Railway deploy automatically.&lt;/p&gt;




&lt;h2&gt;
  
  
  The 10 gotchas
&lt;/h2&gt;

&lt;p&gt;I want to share the gotchas because they are the entire reason this post exists. None of these are documented anywhere. The first six will affect everyone doing this setup. The rest depend on your configuration choices—but if you're adding MCP servers or fallback providers, you'll hit those too.&lt;/p&gt;




&lt;h3&gt;
  
  
  Gotcha 1: &lt;code&gt;gateway start&lt;/code&gt; vs &lt;code&gt;gateway run&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;The Hermes docs (and some examples floating around) reference &lt;code&gt;hermes gateway start&lt;/code&gt;. Don't use that in Docker. It's for host machine services.&lt;/p&gt;

&lt;p&gt;Inside a Docker container, you will get this error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Service start is not applicable inside a Docker container.
Or run the gateway directly: hermes gateway run

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; In your &lt;code&gt;entrypoint.sh&lt;/code&gt;, use &lt;code&gt;exec hermes gateway run&lt;/code&gt;—not &lt;code&gt;start&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;exec &lt;/span&gt;hermes gateway run

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;exec&lt;/code&gt; matters too—it replaces the shell process so tini can properly manage the process tree.&lt;/p&gt;




&lt;h3&gt;
  
  
  Gotcha 2: Volume mount path was wrong
&lt;/h3&gt;

&lt;p&gt;This one cost me the most time. I initially mounted the Railway Volume at &lt;code&gt;/root/.hermes/memories&lt;/code&gt;—just the memories subdirectory—thinking that was the only thing I needed to persist.&lt;/p&gt;

&lt;p&gt;Wrong. Hermes stores a lot more than memories outside that subdirectory:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Gateway state&lt;/li&gt;
&lt;li&gt;Session history (&lt;code&gt;state.db&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Cron jobs&lt;/li&gt;
&lt;li&gt;The home channel setup state&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every deploy wiped all of that, so the bot would come back up and immediately ask me to "set your home channel" as if it had never been configured. Completely stateless on every restart.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; Mount the volume at &lt;code&gt;/root/.hermes&lt;/code&gt;—the entire Hermes home directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;railway volume add &lt;span class="nt"&gt;--mount-path&lt;/span&gt; /root/.hermes

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Gotcha 3: Wrong MCP config key
&lt;/h3&gt;

&lt;p&gt;I burned an embarrassing amount of time on this one. My &lt;code&gt;cli-config.yaml&lt;/code&gt; had:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;mcp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;servers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;my-tool&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://..."&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hermes does not recognize this structure. The correct top-level key is &lt;code&gt;mcp_servers:&lt;/code&gt;—flat, not nested under &lt;code&gt;mcp:&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;mcp_servers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;my-tool&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://..."&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No error is thrown for the wrong key—Hermes just silently ignores the MCP servers entirely. You only notice because your tools don't show up.&lt;/p&gt;




&lt;h3&gt;
  
  
  Gotcha 4: &lt;code&gt;config.yaml&lt;/code&gt; vs &lt;code&gt;cli-config.yaml&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;The sample file in the Hermes repo is named &lt;code&gt;cli-config.yaml.example&lt;/code&gt;. Naturally, I named my file &lt;code&gt;cli-config.yaml&lt;/code&gt;. That works for CLI usage.&lt;/p&gt;

&lt;p&gt;But the &lt;strong&gt;gateway&lt;/strong&gt; reads &lt;code&gt;config.yaml&lt;/code&gt; at runtime. The CLI and the gateway use different config loaders, and they look for different filenames.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; Write your config to both files in &lt;code&gt;entrypoint.sh&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cp&lt;/span&gt; /app/hermes/cli-config.yaml &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HERMES_HOME&lt;/span&gt;&lt;span class="s2"&gt;/cli-config.yaml"&lt;/span&gt;
&lt;span class="nb"&gt;cp&lt;/span&gt; /app/hermes/cli-config.yaml &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HERMES_HOME&lt;/span&gt;&lt;span class="s2"&gt;/config.yaml"&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Maintain one source file in your repo and copy it to both locations on startup. Config changes propagate correctly regardless of which loader is running.&lt;/p&gt;




&lt;h3&gt;
  
  
  Gotcha 5: MCP secrets not reaching Hermes
&lt;/h3&gt;

&lt;p&gt;I had all my MCP secrets set as Railway environment variables. They were there in the Railway dashboard, visibly set, verified. Hermes couldn't see them.&lt;/p&gt;

&lt;p&gt;The issue: Hermes reads secrets from &lt;code&gt;~/.hermes/.env&lt;/code&gt;, not directly from the system environment. My &lt;code&gt;entrypoint.sh&lt;/code&gt; was only writing a handful of variables to that file—not the MCP secrets.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; Write ALL secrets to &lt;code&gt;~/.hermes/.env&lt;/code&gt; in &lt;code&gt;entrypoint.sh&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HERMES_HOME&lt;/span&gt;&lt;span class="s2"&gt;/.env"&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
ANTHROPIC_API_KEY=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;ANTHROPIC_API_KEY&lt;/span&gt;&lt;span class="k"&gt;:-}&lt;/span&gt;&lt;span class="sh"&gt;
TELEGRAM_BOT_TOKEN=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TELEGRAM_BOT_TOKEN&lt;/span&gt;&lt;span class="k"&gt;:-}&lt;/span&gt;&lt;span class="sh"&gt;
TELEGRAM_ALLOWED_USERS=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TELEGRAM_ALLOWED_USERS&lt;/span&gt;&lt;span class="k"&gt;:-}&lt;/span&gt;&lt;span class="sh"&gt;
TELEGRAM_HOME_CHANNEL=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TELEGRAM_HOME_CHANNEL&lt;/span&gt;&lt;span class="k"&gt;:-}&lt;/span&gt;&lt;span class="sh"&gt;
TELEGRAM_HOME_CHANNEL_NAME=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TELEGRAM_HOME_CHANNEL_NAME&lt;/span&gt;&lt;span class="k"&gt;:-}&lt;/span&gt;&lt;span class="sh"&gt;
MY_MCP_SECRET=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;MY_MCP_SECRET&lt;/span&gt;&lt;span class="k"&gt;:-}&lt;/span&gt;&lt;span class="sh"&gt;
NOTION_TOKEN=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NOTION_TOKEN&lt;/span&gt;&lt;span class="k"&gt;:-}&lt;/span&gt;&lt;span class="sh"&gt;
HERMES_HUMAN_DELAY_MODE=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;HERMES_HUMAN_DELAY_MODE&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;natural&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;
HERMES_ACCEPT_HOOKS=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;HERMES_ACCEPT_HOOKS&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;
NOUS_API_KEY=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NOUS_API_KEY&lt;/span&gt;&lt;span class="k"&gt;:-}&lt;/span&gt;&lt;span class="sh"&gt;
&lt;/span&gt;&lt;span class="no"&gt;EOF

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;:-&lt;/code&gt; pattern uses the environment variable if set, empty string if not. Keeps the file clean even if some optional secrets aren't configured yet.&lt;/p&gt;




&lt;h3&gt;
  
  
  Gotcha 6: Agent is completely silent after deploy
&lt;/h3&gt;

&lt;p&gt;After fixing the gateway run command, the bot would start, logs looked clean, no errors—and then complete silence. Send a Telegram message, nothing comes back. No errors, no timeouts, no indication anything was wrong.&lt;/p&gt;

&lt;p&gt;The cause: &lt;code&gt;TELEGRAM_HOME_CHANNEL&lt;/code&gt; was not set. When Hermes doesn't know its home channel, it enters a waiting-for-setup state and ignores incoming messages entirely. It's not an error state—it's just waiting.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; Set &lt;code&gt;TELEGRAM_HOME_CHANNEL&lt;/code&gt; to your Telegram user ID as a Railway environment variable. For a personal DM bot, this is the same as your user ID. Find it by messaging &lt;a href="https://t.me/userinfobot?ref=tessakriesel.com" rel="noopener noreferrer"&gt;@userinfobot&lt;/a&gt; on Telegram.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;railway variables &lt;span class="nb"&gt;set &lt;/span&gt;&lt;span class="nv"&gt;TELEGRAM_HOME_CHANNEL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;123456789

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Gotcha 7: No tini = zombie MCP processes
&lt;/h3&gt;

&lt;p&gt;Hermes runs MCP stdio servers as subprocesses—for example, the Notion MCP runs as &lt;code&gt;npx @notionhq/notion-mcp-server&lt;/code&gt;. Without a proper init system as PID 1, these subprocesses become zombies when they exit. They accumulate over time and eventually cause problems.&lt;/p&gt;

&lt;p&gt;The upstream Hermes Dockerfile uses &lt;code&gt;tini&lt;/code&gt; explicitly for exactly this reason. I missed that detail initially.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; Install tini in your Dockerfile and use it as the entrypoint. Critically, do NOT set a &lt;code&gt;startCommand&lt;/code&gt; in &lt;code&gt;railway.json&lt;/code&gt;—Railway's startCommand overrides the Docker ENTRYPOINT, which means tini never runs. Leave startCommand out and let Railway use the ENTRYPOINT directly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;RUN &lt;/span&gt;apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; tini
&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt;&lt;span class="s"&gt; ["/usr/bin/tini", "-g", "--", "/entrypoint.sh"]&lt;/span&gt;


{
  "build": { "builder": "DOCKERFILE" },
  "deploy": {
    "restartPolicyType": "ON_FAILURE",
    "restartPolicyMaxRetries": 10
  }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;-g&lt;/code&gt; flag means tini will send signals to the entire process group, which matters for subprocess cleanup.&lt;/p&gt;




&lt;h3&gt;
  
  
  Gotcha 8: stdio MCP servers fail to start in the container
&lt;/h3&gt;

&lt;p&gt;If you're using stdio-based MCP servers (like the Notion MCP via &lt;code&gt;npx&lt;/code&gt;), the package has to be downloaded on first invocation. In a Railway container, this download can fail entirely—leaving the MCP server in an infinite retry loop with no useful error message. You won't see a crash. You'll just see your MCP tools never appear and Notion never responds.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; Pre-install the package in the Dockerfile so it's already there when the container starts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;RUN npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @notionhq/notion-mcp-server

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After this, &lt;code&gt;npx&lt;/code&gt; finds the package locally and starts immediately. Do this for every stdio MCP server you configure.&lt;/p&gt;




&lt;h3&gt;
  
  
  Gotcha 9: &lt;code&gt;api_max_retries&lt;/code&gt; too high with fallback providers
&lt;/h3&gt;

&lt;p&gt;I had &lt;code&gt;api_max_retries: 3&lt;/code&gt; in my config. What this means in practice: if Anthropic hits an error or rate limit, Hermes retries the same provider 3 times before trying the fallback. That's potentially 3 failed requests with exponential backoff before you failover.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; Set &lt;code&gt;api_max_retries: 1&lt;/code&gt; when using fallback providers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;agent&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;api_max_retries&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One failure on the primary, immediately tries the fallback.&lt;/p&gt;




&lt;h3&gt;
  
  
  Gotcha 10: Will the volume hide the Hermes install?
&lt;/h3&gt;

&lt;p&gt;When running as root on Linux (Docker default), the Hermes install script puts code at &lt;code&gt;/usr/local/lib/hermes-agent&lt;/code&gt;—not at &lt;code&gt;~/.hermes&lt;/code&gt;. So mounting a volume at &lt;code&gt;/root/.hermes&lt;/code&gt; does NOT hide or overwrite the installed Hermes code. It only covers user config and data.&lt;/p&gt;

&lt;p&gt;I mention this because I spent time wondering whether my volume mount was somehow replacing the install. You don't need to reinstall Hermes on every container start. The install is baked into the image. The volume handles your data only.&lt;/p&gt;




&lt;h2&gt;
  
  
  The full working setup
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Dockerfile
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; python:3.13-slim&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;apt-get update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="nt"&gt;--no-install-recommends&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    curl bash git nodejs npm build-essential tini &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; /var/lib/apt/lists/&lt;span class="k"&gt;*&lt;/span&gt;

&lt;span class="c"&gt;# Pre-install any stdio MCP servers to avoid cold-start downloads&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @notionhq/notion-mcp-server

&lt;span class="c"&gt;# Install Hermes — pinned to a specific commit for reproducibility&lt;/span&gt;
&lt;span class="c"&gt;# Update this SHA when you want to upgrade Hermes&lt;/span&gt;
&lt;span class="k"&gt;ARG&lt;/span&gt;&lt;span class="s"&gt; HERMES_COMMIT=c23a87bc163b188abc7e40fbdccf07a9739231c3&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; &lt;span class="s2"&gt;"https://raw.githubusercontent.com/NousResearch/hermes-agent/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;HERMES_COMMIT&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/scripts/install.sh"&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    | bash &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nt"&gt;--skip-setup&lt;/span&gt;

&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; PATH="/root/.local/bin:${PATH}"&lt;/span&gt;

&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;

&lt;span class="c"&gt;# Sanity check — verify install succeeded&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;hermes &lt;span class="nt"&gt;--version&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; entrypoint.sh /entrypoint.sh&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;chmod&lt;/span&gt; +x /entrypoint.sh

&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 8443&lt;/span&gt;

&lt;span class="c"&gt;# tini as PID 1 to handle zombie subprocess cleanup&lt;/span&gt;
&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt;&lt;span class="s"&gt; ["/usr/bin/tini", "-g", "--", "/entrypoint.sh"]&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  entrypoint.sh
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail

&lt;span class="nv"&gt;HERMES_HOME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;HERMES_HOME&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="p"&gt;/.hermes&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="c"&gt;# Create all directories Hermes expects (volume may be empty on first deploy)&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HERMES_HOME&lt;/span&gt;&lt;span class="s2"&gt;/memories"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
         &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HERMES_HOME&lt;/span&gt;&lt;span class="s2"&gt;/skills"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
         &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HERMES_HOME&lt;/span&gt;&lt;span class="s2"&gt;/sessions"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
         &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HERMES_HOME&lt;/span&gt;&lt;span class="s2"&gt;/cron"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
         &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HERMES_HOME&lt;/span&gt;&lt;span class="s2"&gt;/cron/output"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
         &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HERMES_HOME&lt;/span&gt;&lt;span class="s2"&gt;/hooks"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
         &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HERMES_HOME&lt;/span&gt;&lt;span class="s2"&gt;/logs"&lt;/span&gt;

&lt;span class="c"&gt;# Write config to BOTH filenames — CLI uses cli-config.yaml, gateway uses config.yaml&lt;/span&gt;
&lt;span class="nb"&gt;cp&lt;/span&gt; /app/hermes/cli-config.yaml &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HERMES_HOME&lt;/span&gt;&lt;span class="s2"&gt;/cli-config.yaml"&lt;/span&gt;
&lt;span class="nb"&gt;cp&lt;/span&gt; /app/hermes/cli-config.yaml &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HERMES_HOME&lt;/span&gt;&lt;span class="s2"&gt;/config.yaml"&lt;/span&gt;

&lt;span class="c"&gt;# Write SOUL.md — agent identity/persona&lt;/span&gt;
&lt;span class="nb"&gt;cp&lt;/span&gt; /app/hermes/SOUL.md &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HERMES_HOME&lt;/span&gt;&lt;span class="s2"&gt;/SOUL.md"&lt;/span&gt;

&lt;span class="c"&gt;# Write ALL secrets to ~/.hermes/.env — Hermes reads from here, not system env&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HERMES_HOME&lt;/span&gt;&lt;span class="s2"&gt;/.env"&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
ANTHROPIC_API_KEY=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;ANTHROPIC_API_KEY&lt;/span&gt;&lt;span class="k"&gt;:-}&lt;/span&gt;&lt;span class="sh"&gt;
TELEGRAM_BOT_TOKEN=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TELEGRAM_BOT_TOKEN&lt;/span&gt;&lt;span class="k"&gt;:-}&lt;/span&gt;&lt;span class="sh"&gt;
TELEGRAM_ALLOWED_USERS=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TELEGRAM_ALLOWED_USERS&lt;/span&gt;&lt;span class="k"&gt;:-}&lt;/span&gt;&lt;span class="sh"&gt;
TELEGRAM_HOME_CHANNEL=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TELEGRAM_HOME_CHANNEL&lt;/span&gt;&lt;span class="k"&gt;:-}&lt;/span&gt;&lt;span class="sh"&gt;
TELEGRAM_HOME_CHANNEL_NAME=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TELEGRAM_HOME_CHANNEL_NAME&lt;/span&gt;&lt;span class="k"&gt;:-}&lt;/span&gt;&lt;span class="sh"&gt;
NOTION_TOKEN=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NOTION_TOKEN&lt;/span&gt;&lt;span class="k"&gt;:-}&lt;/span&gt;&lt;span class="sh"&gt;
HERMES_HUMAN_DELAY_MODE=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;HERMES_HUMAN_DELAY_MODE&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;natural&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;
HERMES_ACCEPT_HOOKS=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;HERMES_ACCEPT_HOOKS&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;
NOUS_API_KEY=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NOUS_API_KEY&lt;/span&gt;&lt;span class="k"&gt;:-}&lt;/span&gt;&lt;span class="sh"&gt;
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;span class="nb"&gt;chmod &lt;/span&gt;600 &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HERMES_HOME&lt;/span&gt;&lt;span class="s2"&gt;/.env"&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Hermes config ready. Starting gateway..."&lt;/span&gt;
&lt;span class="nb"&gt;exec &lt;/span&gt;hermes gateway run

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  hermes/cli-config.yaml
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;anthropic/claude-sonnet-4-6"&lt;/span&gt;
  &lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;anthropic"&lt;/span&gt;

&lt;span class="na"&gt;fallback_providers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;nous-api"&lt;/span&gt;
    &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hermes-4-405B"&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;nous-api"&lt;/span&gt;
    &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hermes-4-70B"&lt;/span&gt;

&lt;span class="c1"&gt;# Note: model names vary by Nous Portal plan. Verify yours at portal.nousresearch.com&lt;/span&gt;
&lt;span class="c1"&gt;# before deploying — a wrong model name causes silent fallback failures.&lt;/span&gt;

&lt;span class="na"&gt;terminal&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;backend&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;local"&lt;/span&gt;
  &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;180&lt;/span&gt;

&lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;memory_enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;user_profile_enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;memory_char_limit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4000&lt;/span&gt;
  &lt;span class="na"&gt;user_char_limit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2000&lt;/span&gt;
  &lt;span class="na"&gt;nudge_interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;
  &lt;span class="na"&gt;flush_min_turns&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;6&lt;/span&gt;

&lt;span class="na"&gt;session_reset&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;both&lt;/span&gt;
  &lt;span class="na"&gt;idle_minutes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1440&lt;/span&gt;
  &lt;span class="na"&gt;at_hour&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;

&lt;span class="na"&gt;group_sessions_per_user&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

&lt;span class="na"&gt;agent&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;max_turns&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;60&lt;/span&gt;
  &lt;span class="na"&gt;reasoning_effort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;medium"&lt;/span&gt;
  &lt;span class="na"&gt;api_max_retries&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;

&lt;span class="na"&gt;tool_loop_guardrails&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;warnings_enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;hard_stop_enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

&lt;span class="na"&gt;platform_toolsets&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;cli&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;hermes-cli&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;telegram&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;hermes-telegram&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;session_search&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;# IMPORTANT: top-level key is mcp_servers, NOT mcp.servers&lt;/span&gt;
&lt;span class="na"&gt;mcp_servers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;notion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;npx"&lt;/span&gt;
    &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-y"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;@notionhq/notion-mcp-server"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;NOTION_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;${NOTION_TOKEN}"&lt;/span&gt;
  &lt;span class="c1"&gt;# Add HTTP MCP servers the same way — secrets go in Railway vars and .env&lt;/span&gt;
  &lt;span class="c1"&gt;# my-http-tool:&lt;/span&gt;
  &lt;span class="c1"&gt;# url: "https://your-mcp-endpoint.com/mcp"&lt;/span&gt;
  &lt;span class="c1"&gt;# headers:&lt;/span&gt;
  &lt;span class="c1"&gt;# Authorization: "Bearer ${MY_MCP_SECRET}"&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  railway.json
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"$schema"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://railway.app/railway.schema.json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"builder"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"DOCKERFILE"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"deploy"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"restartPolicyType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ON_FAILURE"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"restartPolicyMaxRetries"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No &lt;code&gt;startCommand&lt;/code&gt; here intentionally. Railway's startCommand overrides Docker's ENTRYPOINT—which means tini never runs if you add one. Leave it out and Railway uses the ENTRYPOINT from the Dockerfile.&lt;/p&gt;




&lt;h2&gt;
  
  
  Railway setup walkthrough
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1. Initialize Railway project&lt;/span&gt;
railway init

&lt;span class="c"&gt;# 2. Initial deploy to create the service&lt;/span&gt;
railway up &lt;span class="nt"&gt;--detach&lt;/span&gt;

&lt;span class="c"&gt;# 3. Link to the service&lt;/span&gt;
railway service &lt;span class="s2"&gt;"your-service-name"&lt;/span&gt;

&lt;span class="c"&gt;# 4. Set environment variables&lt;/span&gt;
railway variables &lt;span class="nb"&gt;set &lt;/span&gt;&lt;span class="nv"&gt;ANTHROPIC_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;sk-ant-...
railway variables &lt;span class="nb"&gt;set &lt;/span&gt;&lt;span class="nv"&gt;TELEGRAM_BOT_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;...
railway variables &lt;span class="nb"&gt;set &lt;/span&gt;&lt;span class="nv"&gt;TELEGRAM_ALLOWED_USERS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;123456789
railway variables &lt;span class="nb"&gt;set &lt;/span&gt;&lt;span class="nv"&gt;TELEGRAM_HOME_CHANNEL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;123456789
railway variables &lt;span class="nb"&gt;set &lt;/span&gt;&lt;span class="nv"&gt;TELEGRAM_HOME_CHANNEL_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Your Name DM"&lt;/span&gt;
railway variables &lt;span class="nb"&gt;set &lt;/span&gt;&lt;span class="nv"&gt;HERMES_HUMAN_DELAY_MODE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;natural
railway variables &lt;span class="nb"&gt;set &lt;/span&gt;&lt;span class="nv"&gt;HERMES_ACCEPT_HOOKS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1
railway variables &lt;span class="nb"&gt;set &lt;/span&gt;&lt;span class="nv"&gt;NOUS_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;...
railway variables &lt;span class="nb"&gt;set &lt;/span&gt;&lt;span class="nv"&gt;NOTION_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;...

&lt;span class="c"&gt;# Optional: webhook mode is more efficient than polling for hosted deployments&lt;/span&gt;
&lt;span class="c"&gt;# railway variables set TELEGRAM_WEBHOOK_URL=https://your-service.up.railway.app/telegram&lt;/span&gt;
&lt;span class="c"&gt;# railway variables set TELEGRAM_WEBHOOK_SECRET=$(openssl rand -hex 32)&lt;/span&gt;

&lt;span class="c"&gt;# 5. Add persistent volume — MUST be /root/.hermes, not a subdirectory&lt;/span&gt;
railway volume add &lt;span class="nt"&gt;--mount-path&lt;/span&gt; /root/.hermes

&lt;span class="c"&gt;# 6. Redeploy to pick up the volume&lt;/span&gt;
railway up &lt;span class="nt"&gt;--detach&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Getting your Telegram IDs:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a bot via &lt;a href="https://t.me/BotFather?ref=tessakriesel.com" rel="noopener noreferrer"&gt;@BotFather&lt;/a&gt; → &lt;code&gt;TELEGRAM_BOT_TOKEN&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Message &lt;a href="https://t.me/userinfobot?ref=tessakriesel.com" rel="noopener noreferrer"&gt;@userinfobot&lt;/a&gt; → your user ID for &lt;code&gt;TELEGRAM_ALLOWED_USERS&lt;/code&gt; and &lt;code&gt;TELEGRAM_HOME_CHANNEL&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;For a personal DM setup, both values are the same&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Auto-deploy on push:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# .git/hooks/post-push&lt;/span&gt;
&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
railway up &lt;span class="nt"&gt;--detach&lt;/span&gt;


&lt;span class="nb"&gt;chmod&lt;/span&gt; +x .git/hooks/post-push

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  What I'd do differently
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Start with the volume at the right path from day one.&lt;/strong&gt; The &lt;code&gt;/root/.hermes&lt;/code&gt; vs &lt;code&gt;/root/.hermes/memories&lt;/code&gt; mistake wasted the most time because the symptom—bot asking to set home channel—looked like a configuration problem, not a persistence problem.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Verify MCP tools are loading before assuming they work.&lt;/strong&gt; Ask Hermes directly: "What MCP tools do you have available?" If it lists nothing, you've got a config key problem or a secrets problem. Don't assume silence means they're loading quietly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Set &lt;code&gt;TELEGRAM_HOME_CHANNEL&lt;/code&gt; before your first deploy.&lt;/strong&gt; The silent-bot symptom with no logs is deeply confusing. Just have this set from the start.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quick reference: the 10 gotchas
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;Problem&lt;/th&gt;
&lt;th&gt;Fix&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;gateway start&lt;/code&gt; fails in Docker&lt;/td&gt;
&lt;td&gt;Use &lt;code&gt;hermes gateway run&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Bot resets on every deploy&lt;/td&gt;
&lt;td&gt;Mount volume at &lt;code&gt;/root/.hermes&lt;/code&gt;, not a subdirectory&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;MCP servers silently ignored&lt;/td&gt;
&lt;td&gt;Config key is &lt;code&gt;mcp_servers:&lt;/code&gt;, not &lt;code&gt;mcp.servers:&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Gateway ignores your config&lt;/td&gt;
&lt;td&gt;Copy config to both &lt;code&gt;cli-config.yaml&lt;/code&gt; AND &lt;code&gt;config.yaml&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;MCP secrets not available&lt;/td&gt;
&lt;td&gt;Write all secrets to &lt;code&gt;~/.hermes/.env&lt;/code&gt; in entrypoint&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;Bot starts but never responds&lt;/td&gt;
&lt;td&gt;Set &lt;code&gt;TELEGRAM_HOME_CHANNEL&lt;/code&gt; env var&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;Zombie subprocess accumulation&lt;/td&gt;
&lt;td&gt;Install and use &lt;code&gt;tini&lt;/code&gt; as PID 1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;MCP stdio server cold-start delay&lt;/td&gt;
&lt;td&gt;Pre-install packages in Dockerfile&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;Slow LLM failover&lt;/td&gt;
&lt;td&gt;Set &lt;code&gt;api_max_retries: 1&lt;/code&gt; when using fallback providers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;Will volume hide the Hermes install?&lt;/td&gt;
&lt;td&gt;No—install is at system path, volume is for data only&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




</description>
      <category>ai</category>
      <category>automation</category>
      <category>devops</category>
    </item>
    <item>
      <title>How to Measure Time-to-Value for Your API (Without a Data Team or Custom Analytics Build)</title>
      <dc:creator>Tessa Kriesel</dc:creator>
      <pubDate>Wed, 11 Mar 2026 19:37:03 +0000</pubDate>
      <link>https://dev.to/builtfordevs/how-to-measure-time-to-value-for-your-api-without-a-data-team-or-custom-analytics-build-5029</link>
      <guid>https://dev.to/builtfordevs/how-to-measure-time-to-value-for-your-api-without-a-data-team-or-custom-analytics-build-5029</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.unsplash.com%2Fphoto-1501139083538-0139583c060f%3Fcrop%3Dentropy%26cs%3Dtinysrgb%26fit%3Dmax%26fm%3Djpg%26ixid%3DM3wxMTc3M3wwfDF8c2VhcmNofDF8fHRpbWV8ZW58MHx8fHwxNzczMTg5MTIxfDA%26ixlib%3Drb-4.1.0%26q%3D80%26w%3D2000" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.unsplash.com%2Fphoto-1501139083538-0139583c060f%3Fcrop%3Dentropy%26cs%3Dtinysrgb%26fit%3Dmax%26fm%3Djpg%26ixid%3DM3wxMTc3M3wwfDF8c2VhcmNofDF8fHRpbWV8ZW58MHx8fHwxNzczMTg5MTIxfDA%26ixlib%3Drb-4.1.0%26q%3D80%26w%3D2000" alt="How to Measure Time-to-Value for Your API (Without a Data Team or Custom Analytics Build)" width="2000" height="1333"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You don't know your TTV. I'm willing to bet on it.&lt;/p&gt;

&lt;p&gt;Not because you're not tracking things. You probably have a dashboard full of signups, API calls, session lengths, and something labeled "activation rate" that nobody has ever cleanly defined. You're tracking plenty. You're just not tracking the right thing.&lt;/p&gt;

&lt;p&gt;Here's why that matters: developers who don't reach value fast leave fast. And you won't know they were ever close until they're already gone.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem With Activity Metrics
&lt;/h2&gt;

&lt;p&gt;Most API founders measure activity and call it progress. Sound familiar?&lt;/p&gt;

&lt;p&gt;You end up tracking things like time to first API call, number of calls in the first session, or completion of an onboarding checklist. These metrics tell you a developer showed up and touched your product. They don't tell you whether that developer got what they came for.&lt;/p&gt;

&lt;p&gt;Here's where it breaks down. The developer who made 3 API calls and churned looks identical in your data to the developer who made 3 API calls and became a power user. Until you look at whether they hit your Value Moment.&lt;/p&gt;

&lt;p&gt;You're measuring motion, not progress. That's the real problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is a Value Moment?
&lt;/h2&gt;

&lt;p&gt;Your Value Moment is the specific interaction where a developer gets undeniable proof that your API does what they need it to do.&lt;/p&gt;

&lt;p&gt;Not "they called the endpoint." Not "they saw a response." The moment they got a result that made them think: &lt;em&gt;okay, this actually works for my use case.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It looks different for every product:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For a payments API, it's the first successful test transaction in their dev environment&lt;/li&gt;
&lt;li&gt;For a speech-to-text API, it's the first transcript that returns with over 95% accuracy on their test audio&lt;/li&gt;
&lt;li&gt;For an AI completions API, it's the first response that matches their expected output format&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Value Moment is not generic. It's specific to what your product actually does. And it's almost always one concrete event, not a sequence.&lt;/p&gt;

&lt;p&gt;Your TTV is the gap between signup and that moment. That's it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Value Moment Method: Define It, Track It, Fix It
&lt;/h2&gt;

&lt;p&gt;You can define your Value Moment and start measuring TTV in an afternoon. Here's exactly how.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Define Your Value Moment
&lt;/h3&gt;

&lt;p&gt;Pull up data on your best-retained developers, the ones who've been active 60+ days. What did they do in the first 24 hours that churned developers almost never did?&lt;/p&gt;

&lt;p&gt;You're looking for one identifiable event. If you can't access the data yet, interview three to five developers who successfully integrated your API. Ask them: "What was the moment you knew this was going to work?" Their answers will cluster around one or two specific interactions.&lt;/p&gt;

&lt;p&gt;That cluster is your Value Moment. Write it down in plain language: "A developer successfully [specific action] with our API." That sentence is the foundation of everything else.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Identify the Signal
&lt;/h3&gt;

&lt;p&gt;Your Value Moment needs to map to something your system actually logs: an event, a response code, a specific API call.&lt;/p&gt;

&lt;p&gt;For most APIs this is straightforward. If your Value Moment is "first successful test transaction," your signal is probably &lt;code&gt;transaction.success&lt;/code&gt; with a test-mode flag. If it's "first accurate transcript returned," your signal might be a response with a confidence score above your threshold.&lt;/p&gt;

&lt;p&gt;If your system doesn't log the signal you need, that's a one-line tracking addition, not an analytics overhaul. Add the event, tag it as your Value Moment signal, move on.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Measure the Gap
&lt;/h3&gt;

&lt;p&gt;TTV = time from signup to first Value Moment signal.&lt;/p&gt;

&lt;p&gt;That's the whole formula. You're not averaging session lengths or weighting engagement scores. You're measuring one gap: how long does it take a developer to get their first undeniable proof your API works?&lt;/p&gt;

&lt;p&gt;Track it for every new developer who signs up. Over time you'll have a distribution. What's the median? What's the 75th percentile? And the number that really matters: what percentage of developers hit the Value Moment at all within their first 7 days?&lt;/p&gt;

&lt;p&gt;That last number explains your retention curve better than anything else in your dashboard.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to Do With Your TTV Number
&lt;/h2&gt;

&lt;p&gt;Your TTV number tells you two things immediately.&lt;/p&gt;

&lt;p&gt;First, whether your onboarding is actually working. If the median TTV for developers who stay long-term is 18 minutes and your current median is 4 hours, that gap is your onboarding problem. Not your product. Your onboarding.&lt;/p&gt;

&lt;p&gt;Second, where your intervention window is. Developers who don't hit the Value Moment in their first session almost never come back. That's not a judgment call, it's a pattern. Your job is to get them there before that window closes.&lt;/p&gt;

&lt;p&gt;From here you optimize by working backward from the Value Moment. What's the friction between signup and that first signal? Where do developers drop off before they get there? Those are the specific things to fix. Not "improve the docs" or "add more examples" in the abstract, but the precise steps between where developers start and where they need to get.&lt;/p&gt;

&lt;h2&gt;
  
  
  See Your TTV Before It Shows Up in Your Churn Report
&lt;/h2&gt;

&lt;p&gt;Here's the bottom line: defining your Value Moment takes an afternoon. Watching TTV data accumulate manually, correlating it against retention, turning it into something you can actually act on? That takes a lot longer.&lt;/p&gt;

&lt;p&gt;That's what Built for Devs handles for you. Sign up, define your Value Moment, and as new developers flow through your onboarding, you'll see your TTV in your dashboard automatically. No custom analytics pipeline required.&lt;/p&gt;

&lt;p&gt;You don't need a data team to start. You need to define the right moment, then let the tool do the tracking.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://builtfor.dev/score?ref=blog.builtfor.dev" rel="noopener noreferrer"&gt;Start measuring your developer TTV →&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgbalq27aweul7l6ea071.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgbalq27aweul7l6ea071.png" alt="How to Measure Time-to-Value for Your API (Without a Data Team or Custom Analytics Build)" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;View of Built for Devs Dashboard&lt;/em&gt;&lt;/p&gt;

</description>
      <category>api</category>
      <category>tools</category>
      <category>devrel</category>
    </item>
    <item>
      <title>Stop asking developers what they think. Watch what they do.</title>
      <dc:creator>Tessa Kriesel</dc:creator>
      <pubDate>Tue, 10 Mar 2026 17:55:12 +0000</pubDate>
      <link>https://dev.to/builtfordevs/stop-asking-developers-what-they-think-watch-what-they-do-4k9b</link>
      <guid>https://dev.to/builtfordevs/stop-asking-developers-what-they-think-watch-what-they-do-4k9b</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.unsplash.com%2Fphoto-1530210124550-912dc1381cb8%3Fcrop%3Dentropy%26cs%3Dtinysrgb%26fit%3Dmax%26fm%3Djpg%26ixid%3DM3wxMTc3M3wwfDF8c2VhcmNofDI2fHx0aGlua2luZ3xlbnwwfHx8fDE3NzMxMTA0MzV8MA%26ixlib%3Drb-4.1.0%26q%3D80%26w%3D2000" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.unsplash.com%2Fphoto-1530210124550-912dc1381cb8%3Fcrop%3Dentropy%26cs%3Dtinysrgb%26fit%3Dmax%26fm%3Djpg%26ixid%3DM3wxMTc3M3wwfDF8c2VhcmNofDI2fHx0aGlua2luZ3xlbnwwfHx8fDE3NzMxMTA0MzV8MA%26ixlib%3Drb-4.1.0%26q%3D80%26w%3D2000" alt="Stop asking developers what they think. Watch what they do." width="2000" height="1334"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ask a developer how your onboarding went and they'll probably say it was fine. Maybe a little long. Could use better docs. You take notes, you nod, you move on.&lt;/p&gt;

&lt;p&gt;What they won't tell you: they almost quit twice, they couldn't find the API reference without Googling, and the moment they hit your pricing page they had to go back and re-read the docs before they trusted you enough to continue.&lt;/p&gt;

&lt;p&gt;That version of events lives in their behavior. Not in their answers.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem isn't your feedback. It's what feedback can't capture.
&lt;/h2&gt;

&lt;p&gt;You're getting feedback. You're talking to users. You're doing the things the startup playbook says to do. But the signal you're collecting is optimized for your comfort, not your understanding.&lt;/p&gt;

&lt;p&gt;When a developer answers "was that confusing?", they don't replay the experience. They construct a memory of it—filtered through what they think you want to hear, how competent they want to appear, and what they've already forgotten. They won't tell you your onboarding took 47 minutes and they almost quit three times. They'll say it was "a little long, but fine." They self-censor because they've moved on and don't remember the exact sticking points.&lt;/p&gt;

&lt;p&gt;That's not dishonesty. That's just how memory works.&lt;/p&gt;

&lt;p&gt;The enemy isn't your users. It's the method you're using to understand them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Behavior tells you what answers can't
&lt;/h2&gt;

&lt;p&gt;Your existing users have context. They've learned your product, forgiven its rough edges, built workarounds. They're not starting from scratch—they're showing you what a loyalist does, not what a new developer does. Your network is worse. They want to be helpful. They'll push through friction that would make a stranger quit.&lt;/p&gt;

&lt;p&gt;What you need is a developer who actually matches the profile of someone you're trying to win—not a friend, not a power user, not someone already in your orbit. The friction that matters is what happens before they care about you. Before they've decided to give you the benefit of the doubt.&lt;/p&gt;

&lt;p&gt;What you see when that developer tries your product for the first time will not match what your feedback sessions told you.&lt;/p&gt;

&lt;p&gt;You'll see where they actually get stuck—not where they said they got stuck. You'll see the moment they almost quit. You'll see the exact point where your product either earns their trust or loses it. And you'll see things you never thought to ask about, because you didn't know they were problems.&lt;/p&gt;

&lt;p&gt;One founder we worked with discovered this the hard way. Their onboarding requested full Google Drive permissions when all they actually needed was access to a single spreadsheet. Feedback sessions didn't surface it. But when they started watching real developers go through the flow—and listening to what those developers said out loud—they found something no form had captured: developers were genuinely annoyed. Many said they would never grant those permissions. Nobody had written that in a feedback session because nobody asks "how do you feel about our OAuth scope?"&lt;/p&gt;

&lt;p&gt;Most founders who go from asking to watching describe the same experience: they thought they knew their onboarding flow. They'd walked through it dozens of times. Then they watched a real developer do it and saw three failure points they'd never once noticed—because they already knew where everything was.&lt;/p&gt;

&lt;p&gt;You know your product too well to use it naively. A developer who's never seen it before doesn't. That's exactly why their experience is the one worth watching.&lt;/p&gt;

&lt;h2&gt;
  
  
  The cost of collecting the wrong signal
&lt;/h2&gt;

&lt;p&gt;With limited runway, every product bet has a price. The features you ship in the next two months either move retention or they don't. If those decisions are grounded in self-reported feedback, you're making expensive guesses dressed up as research.&lt;/p&gt;

&lt;p&gt;There's a specific kind of founder regret that comes from shipping a big feature, watching it go unused, and then finding out through a casual conversation that the feature developers actually needed was something much simpler. Something they never mentioned in a feedback session because they didn't think you'd want to hear it, or they'd already found a workaround and stopped thinking about it.&lt;/p&gt;

&lt;p&gt;That regret is avoidable. Not by doing more research. By doing a different kind.&lt;/p&gt;

&lt;h2&gt;
  
  
  The signal you can't collect any other way
&lt;/h2&gt;

&lt;p&gt;The only way to get honest signal is to watch a developer who's never seen your product try to use it—without context, without guidance, without anyone from your team in the room. No prompts. No hand-holding. Just a real developer and your product.&lt;/p&gt;

&lt;p&gt;The problem is finding them. Not just any developer—one who actually looks like the developer you're trying to win. Your network is limited. Your existing users aren't starting from zero. There's no obvious place to find the right people with zero prior exposure—so most founders never get there at all.&lt;/p&gt;

&lt;p&gt;That's the problem &lt;a href="https://builtfor.dev/?ref=blog.builtfor.dev" rel="noopener noreferrer"&gt;Built for Devs&lt;/a&gt; solves. We match real developers who fit the profile of your target user, bring them to your product for the first time, and capture everything—every click, every hesitation, every moment they say "this makes no sense" out loud. That data powers a findings report that tells you precisely where the experience breaks and what to fix first. Not a list of opinions. A prioritized action plan grounded in real behavior.&lt;/p&gt;

&lt;p&gt;That discomfort of watching someone struggle through something you built—that's the data you've been missing.&lt;/p&gt;

</description>
      <category>startup</category>
      <category>tools</category>
      <category>devrel</category>
    </item>
    <item>
      <title>Why Developers Aren't Coming Back After Their First Session</title>
      <dc:creator>Tessa Kriesel</dc:creator>
      <pubDate>Mon, 09 Mar 2026 14:50:57 +0000</pubDate>
      <link>https://dev.to/builtfordevs/why-developers-arent-coming-back-after-their-first-session-1f3b</link>
      <guid>https://dev.to/builtfordevs/why-developers-arent-coming-back-after-their-first-session-1f3b</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.unsplash.com%2Fphoto-1584105154398-99080f81b8ee%3Fcrop%3Dentropy%26cs%3Dtinysrgb%26fit%3Dmax%26fm%3Djpg%26ixid%3DM3wxMTc3M3wwfDF8c2VhcmNofDF8fGNsb3NlZCUyMGRvb3J8ZW58MHx8fHwxNzczMDY2ODk4fDA%26ixlib%3Drb-4.1.0%26q%3D80%26w%3D2000" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.unsplash.com%2Fphoto-1584105154398-99080f81b8ee%3Fcrop%3Dentropy%26cs%3Dtinysrgb%26fit%3Dmax%26fm%3Djpg%26ixid%3DM3wxMTc3M3wwfDF8c2VhcmNofDF8fGNsb3NlZCUyMGRvb3J8ZW58MHx8fHwxNzczMDY2ODk4fDA%26ixlib%3Drb-4.1.0%26q%3D80%26w%3D2000" alt="Why Developers Aren't Coming Back After Their First Session" width="2000" height="1333"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You've fixed the tutorial. You've cleaned up the docs. You've killed the bugs early users reported. Developers still aren't coming back.&lt;/p&gt;

&lt;p&gt;If this is your situation, you're probably running the same troubleshooting loop most founders run: something about the product isn't clicking. So you improve the product. You add a better onboarding flow. You write a getting-started guide. You watch the metrics. Nothing changes.&lt;/p&gt;

&lt;p&gt;Here's what I keep seeing across dev tool companies stuck in this loop: the diagnosis is wrong. First-session churn usually isn't a product problem. It's a stage problem. And if you're measuring product metrics to fix a stage problem, you're going to keep shipping features that don't move retention.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Onboarding Loop That Goes Nowhere
&lt;/h2&gt;

&lt;p&gt;Most founders respond to first-session churn by improving onboarding. This makes sense on the surface—developers aren't coming back, so something about their first experience isn't working, so you fix the first experience.&lt;/p&gt;

&lt;p&gt;The problem is that "first experience" and "first session" aren't the same thing. The onboarding flow is one slice of the first session. But a developer's first session spans a journey that started before they ever opened your product—and continues through stages that have nothing to do with your tutorial.&lt;/p&gt;

&lt;p&gt;When you only measure what happens inside your product during session one, you're measuring a fraction of what actually determines whether someone comes back. You can optimize that fraction indefinitely and never touch the part that matters.&lt;/p&gt;

&lt;p&gt;I call this stage blindness: diagnosing developer churn with product metrics when the drop-off is happening at the journey level.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Developers Actually Exit
&lt;/h2&gt;

&lt;p&gt;There's a framework I use to think about how developers move through any tool's ecosystem. Five stages: Discover, Evaluate, Learn, Build, Scale.&lt;/p&gt;

&lt;p&gt;Most first-session exits happen in Evaluate and Learn. Not Build.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Discover&lt;/strong&gt; is how they found you—search, a recommendation, a conference talk. If they're in your product, they've cleared Discover.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Evaluate&lt;/strong&gt; is the decision stage. Before a developer commits to learning anything, they're asking a question you probably can't see on your dashboard: &lt;em&gt;is this actually for me?&lt;/em&gt; They're scanning docs, reading changelog entries, checking the GitHub repo, looking at the community, reviewing pricing. They're trying to answer the question fast, before they invest real time. If your product doesn't give them a fast, clear answer, they're gone—and they look like a session-one exit, but the real exit happened during Evaluate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Learn&lt;/strong&gt; is where developers start building skills, not building product. They're running the quickstart. They're working through examples. They're hitting friction and deciding whether the friction is temporary (learning curve) or permanent (bad product fit). If the gap between your quickstart and real-world usage is too big, or if the docs assume knowledge they don't have, they exit here. Again, looks like session-one churn. Actually a stage failure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Build&lt;/strong&gt; is where most onboarding optimization is aimed. More tutorials, better error messages, cleaner UI. The problem: if developers are exiting in Evaluate and Learn, they never make it to Build. Improving Build doesn't help.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scale&lt;/strong&gt; is retention at depth—developers who've integrated your tool and are now spreading it to their team or expanding usage. You don't have a Scale problem if you're seeing first-session exits. But you won't get there without clearing the earlier stages.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Stage Blindness Costs You
&lt;/h2&gt;

&lt;p&gt;When you can't see which stage developers are exiting, you default to shipping. More features, more onboarding improvements, more docs. I've watched companies spend a quarter iterating on their Build experience when their real problem was an Evaluate stage that left developers unsure whether the tool was even meant for them.&lt;/p&gt;

&lt;p&gt;The compounding cost: every iteration cycle you spend in the wrong stage is a cycle you're not spending on the right one. And with 4-6 months of runway, you don't have many cycles left.&lt;/p&gt;

&lt;p&gt;The other cost is signal distortion. When you're measuring product engagement during session one and attributing poor retention to product quality, you're training yourself to look in the wrong place. The feedback loop reinforces the wrong diagnosis.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Diagnose Which Stage Is Failing
&lt;/h2&gt;

&lt;p&gt;You can't improve what you can't see. The starting point is mapping your developer journey with enough specificity to identify where the drop-off actually happens.&lt;/p&gt;

&lt;p&gt;Start with Evaluate. What does a developer experience between finding your product and deciding to invest time in it? What questions are they trying to answer? How fast can they answer them? If you don't know, your Evaluate stage might be invisible to you—which is exactly the problem.&lt;/p&gt;

&lt;p&gt;Then look at Learn. What's the gap between your quickstart and a real use case? Where does that first "wait, this doesn't work the way I expected" moment happen? That's usually where Learn exits occur.&lt;/p&gt;

&lt;p&gt;If you want a fast read on where your developer journey is failing, take the Developer Adoption Score at &lt;a href="https://builtfor.dev/score?ref=blog.builtfor.dev" rel="noopener noreferrer"&gt;builtfor.dev/score&lt;/a&gt;. Free, about 5 minutes, and it gives you an actual score on your journey—not a generic 'improve your onboarding' recommendation. Want to go deeper? Our product offering tracks real developer behavior across every stage so you can see exactly where the drop-off happens.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl2tudh7jukqk8r05p8ms.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl2tudh7jukqk8r05p8ms.png" alt="Why Developers Aren't Coming Back After Their First Session" width="800" height="484"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Developer Journey Tracking in the Pro Plan&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Real Question to Ask
&lt;/h2&gt;

&lt;p&gt;The next time a developer doesn't come back after session one, the question isn't "what was wrong with their first experience?" The question is "which stage failed them?"&lt;/p&gt;

&lt;p&gt;Those are different questions with different answers. And until you can ask the right one, the onboarding loop keeps going.&lt;/p&gt;

&lt;p&gt;You've already tried fixing the product. That's not what's broken.&lt;/p&gt;

</description>
      <category>startup</category>
      <category>tooling</category>
      <category>devrel</category>
    </item>
    <item>
      <title>The 3 Signals That Tell You Whether to Rebuild or Improve Your Dev Tool Onboarding</title>
      <dc:creator>Tessa Kriesel</dc:creator>
      <pubDate>Mon, 09 Mar 2026 04:57:13 +0000</pubDate>
      <link>https://dev.to/builtfordevs/the-3-signals-that-tell-you-whether-to-rebuild-or-improve-your-dev-tool-onboarding-2iim</link>
      <guid>https://dev.to/builtfordevs/the-3-signals-that-tell-you-whether-to-rebuild-or-improve-your-dev-tool-onboarding-2iim</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.unsplash.com%2Fphoto-1709593729967-f490f19a7a96%3Fcrop%3Dentropy%26cs%3Dtinysrgb%26fit%3Dmax%26fm%3Djpg%26ixid%3DM3wxMTc3M3wwfDF8c2VhcmNofDY1fHxzdG9wbGlnaHR8ZW58MHx8fHwxNzczMDMyMTA5fDA%26ixlib%3Drb-4.1.0%26q%3D80%26w%3D2000" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.unsplash.com%2Fphoto-1709593729967-f490f19a7a96%3Fcrop%3Dentropy%26cs%3Dtinysrgb%26fit%3Dmax%26fm%3Djpg%26ixid%3DM3wxMTc3M3wwfDF8c2VhcmNofDY1fHxzdG9wbGlnaHR8ZW58MHx8fHwxNzczMDMyMTA5fDA%26ixlib%3Drb-4.1.0%26q%3D80%26w%3D2000" alt="The 3 Signals That Tell You Whether to Rebuild or Improve Your Dev Tool Onboarding" width="2000" height="1333"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Most teams are having the wrong argument. The debate isn't "should we rebuild"—it's whether you've looked at the right data first.&lt;/p&gt;

&lt;p&gt;I've pulled more than a few product teams out of this exact trap—one that burned a quarter rebuilding their onboarding to see activation barely move, another that iterated for six months on a flow with a structural problem from the start, adding tooltips and reorganizing steps while the actual issue sat untouched two layers deeper.&lt;/p&gt;

&lt;p&gt;Here's what both teams had in common: they made the rebuild vs. improve call based on instinct and internal pressure, not signal.&lt;/p&gt;

&lt;p&gt;That's fixable.&lt;/p&gt;

&lt;h2&gt;
  
  
  The real problem with this decision
&lt;/h2&gt;

&lt;p&gt;When activation flatlines, the conversation usually goes one of two ways.&lt;/p&gt;

&lt;p&gt;The first: "We've been incrementally improving this for months. It's time to rebuild." This feels decisive. But it's often a reaction to frustration, not evidence. Rebuilding satisfies the internal need to feel like you're taking bold action. It doesn't automatically address the root cause.&lt;/p&gt;

&lt;p&gt;The second: "A full rebuild is too expensive right now. Let's keep iterating." This feels prudent. But if the current flow has a structural problem—a wrong assumption about what developers need to experience first, or a sequence that doesn't match how they actually think—iterating around it will only produce marginal gains. You're polishing something that needs to be torn down.&lt;/p&gt;

&lt;p&gt;Neither instinct is wrong, exactly. They just aren't grounded in what the data can actually tell you.&lt;/p&gt;

&lt;p&gt;There are three signals that cut through the argument. I've seen them hold up across enough developer products to trust them. And the time it takes to check all three is probably less than your next sprint planning meeting.&lt;/p&gt;

&lt;h2&gt;
  
  
  Signal 1: Where in the journey is the drop-off happening?
&lt;/h2&gt;

&lt;p&gt;This one requires you to be honest about what "activation" actually means for your product. Not sign-up. Not email confirmation. The moment a developer has experienced enough of your product to understand whether it solves their problem.&lt;/p&gt;

&lt;p&gt;Now look at your drop-off data. Where are developers leaving?&lt;/p&gt;

&lt;p&gt;If developers are dropping off before they've had the chance to reach that value moment—before the first API call, before the first integration runs, before they've gotten any output at all—that's usually a rebuild signal. The problem isn't that your steps are confusing or your copy is unclear. The problem is that the path to value is too long, or the framing at the front end is creating the wrong expectations, or developers aren't self-selecting correctly before they start.&lt;/p&gt;

&lt;p&gt;The instinct in this situation is to improve the steps right before the drop-off. But drop-off location is telling you something different: it's showing you where the gap between developer expectation and product reality became too wide to cross. If that gap opens before developers have experienced core value at all, improving the surrounding steps won't close it. The architecture is wrong—the flow is asking developers to commit before they understand what they're committing to.&lt;/p&gt;

&lt;p&gt;That's not an iteration problem. That's a structural one.&lt;/p&gt;

&lt;p&gt;If your drop-off is concentrated in the middle or later stages—after developers have had initial contact with the core value, but before they've completed the full flow—that's more often an improvement opportunity. The structure is right. There's friction you haven't removed yet.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The signal:&lt;/strong&gt; Drop-off concentrated before value exposure means rebuild. Drop-off concentrated after value exposure means improve.&lt;/p&gt;

&lt;h2&gt;
  
  
  Signal 2: Does completing onboarding predict activation?
&lt;/h2&gt;

&lt;p&gt;This one surprises teams every time they run it. Pull two cohorts: developers who completed your onboarding flow, and developers who skipped it and went straight to your docs. Compare activation rates.&lt;/p&gt;

&lt;p&gt;If developers who completed onboarding activate at significantly higher rates than those who skipped it, your flow is doing something useful. The signal-to-noise ratio is there. You have a structure worth improving.&lt;/p&gt;

&lt;p&gt;If the difference is small—or if developers who skipped onboarding activate at similar or better rates—that's a different story. It means your onboarding isn't providing something developers couldn't find themselves. They're working around it. That's a structural indictment, not an execution one.&lt;/p&gt;

&lt;p&gt;When developers route around your designed path and still succeed, it usually means the flow is optimized around internal assumptions about what developers need—not around what they actually do to reach value. The flow reflects how your team thinks about the product, not how developers experience it. You can improve that flow indefinitely. You're improving the wrong thing.&lt;/p&gt;

&lt;p&gt;The variation worth watching: if high-ICP developers skip onboarding and succeed, but lower-ICP developers complete it and still don't activate, your onboarding might be serving the wrong segment. That's a rebuild with a different diagnosis—you're building onboarding for developers who don't need it, instead of for the ones who do.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The signal:&lt;/strong&gt; Completion predicts activation means improve. Completion and activation are uncorrelated means rebuild.&lt;/p&gt;

&lt;h2&gt;
  
  
  Signal 3: Has friction migrated without completion rates improving?
&lt;/h2&gt;

&lt;p&gt;This is the one that tells you whether you've been iterating in circles.&lt;/p&gt;

&lt;p&gt;Pull the last three iterations of your onboarding. For each one: where was the primary drop-off point, and what was the overall completion rate?&lt;/p&gt;

&lt;p&gt;If the friction point has moved between iterations—step 4 became step 5 became step 7—but the completion rate hasn't meaningfully improved, you've been relocating friction, not removing it. Developers are hitting the same resistance; it's just showing up in a different place now.&lt;/p&gt;

&lt;p&gt;This is the clearest rebuild signal in the data. It tells you there's a load-bearing structural issue that iteration hasn't touched. The friction isn't in the steps. It's in the assumption the steps are built on.&lt;/p&gt;

&lt;p&gt;When the problem location moves but completion doesn't improve, you haven't solved anything—you've relocated the resistance. Eventually teams stop noticing that the friction point keeps shifting because each iteration feels like progress. It's not. You're rebuilding the same wall in a different spot.&lt;/p&gt;

&lt;p&gt;If friction is migrating but completion is improving—say, from 30% to 45% to 55%—that's a healthy iteration signal. Keep going. The structure is sound and the changes are working.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The signal:&lt;/strong&gt; Friction migrates, completion stays flat means rebuild. Friction migrates, completion improves means improve.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the three signals combine
&lt;/h2&gt;

&lt;p&gt;You rarely need all three to point the same direction to get clarity. Here's how I use them:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Two or more signals point to rebuild:&lt;/strong&gt; Stop iterating. You're spending engineering time on the wrong problem. Rebuild means rethinking the journey architecture—what the flow is trying to accomplish, in what order, for which developer. Not just a new UI.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One signal points to rebuild, others are inconclusive:&lt;/strong&gt; Dig deeper before committing. One anomaly is worth investigating; it might be segment-specific or explained by another variable. But don't dismiss it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;All signals point to improve:&lt;/strong&gt; Good news—you have a structural foundation worth building on. The work ahead is meaningful friction removal, clearer copy, better error handling, tighter time-to-value within the existing architecture.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No signals point to rebuild and activation is still flat:&lt;/strong&gt; Look upstream. The problem might not be in your onboarding at all. It might be in how developers arrive—the expectations your marketing and content are creating before they sign up. Fixing the flow won't fix a positioning mismatch.&lt;/p&gt;

&lt;h2&gt;
  
  
  One more thing before you start
&lt;/h2&gt;

&lt;p&gt;The instinct call usually costs you a quarter. Occasionally it costs two. The three signals cost an afternoon with your analytics.&lt;/p&gt;

&lt;p&gt;That's worth doing before you walk into the sprint planning meeting and announce a rebuild that might be the wrong call—or commit to another round of improvements on a flow that needs to be torn down.&lt;/p&gt;

&lt;p&gt;If you want to know where your developer journey is actually breaking, the &lt;a href="https://builtfor.dev/score?ref=blog.builtfor.dev" rel="noopener noreferrer"&gt;Developer Adoption Score&lt;/a&gt; is a free tool that evaluates your current experience across all five stages. It takes about ten minutes and gives you a starting point for this kind of diagnosis.&lt;/p&gt;

&lt;p&gt;The debate teams have about rebuild vs. improve is usually the right debate. They're just having it without the data that would make it productive.&lt;/p&gt;

</description>
      <category>startup</category>
      <category>tooling</category>
      <category>devrel</category>
    </item>
    <item>
      <title>Why Developers Drop Off Before Their First API Call (And How to Fix It)</title>
      <dc:creator>Tessa Kriesel</dc:creator>
      <pubDate>Sun, 08 Mar 2026 04:05:16 +0000</pubDate>
      <link>https://dev.to/builtfordevs/why-developers-drop-off-before-their-first-api-call-and-how-to-fix-it-h8a</link>
      <guid>https://dev.to/builtfordevs/why-developers-drop-off-before-their-first-api-call-and-how-to-fix-it-h8a</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.unsplash.com%2Fphoto-1591522811280-a8759970b03f%3Fcrop%3Dentropy%26cs%3Dtinysrgb%26fit%3Dmax%26fm%3Djpg%26ixid%3DM3wxMTc3M3wwfDF8c2VhcmNofDV8fHRoaW5rfGVufDB8fHx8MTc3Mjk0MjUxNnww%26ixlib%3Drb-4.1.0%26q%3D80%26w%3D2000" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.unsplash.com%2Fphoto-1591522811280-a8759970b03f%3Fcrop%3Dentropy%26cs%3Dtinysrgb%26fit%3Dmax%26fm%3Djpg%26ixid%3DM3wxMTc3M3wwfDF8c2VhcmNofDV8fHRoaW5rfGVufDB8fHx8MTc3Mjk0MjUxNnww%26ixlib%3Drb-4.1.0%26q%3D80%26w%3D2000" alt="Why Developers Drop Off Before Their First API Call (And How to Fix It)" width="2000" height="1333"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You've watched developers sign up, poke around, and disappear—all before making a single API call. You've checked the docs. You've improved the getting-started guide. Rewritten the quickstart. Added tooltips. The drop-off didn't move.&lt;/p&gt;

&lt;p&gt;So you add more docs. Better docs. You hire someone to clean up the copy. You obsess over the first-run experience. Still nothing.&lt;/p&gt;

&lt;p&gt;Here's what's actually happening: you've been fixing the wrong thing.&lt;/p&gt;

&lt;p&gt;Developer drop-off before the first API call is almost never a documentation problem. It's a design assumption problem. And the assumption at the center of it is one almost every dev tool founder makes without realizing it.&lt;/p&gt;

&lt;p&gt;You designed your onboarding for the developer who already knows why they're there.&lt;/p&gt;

&lt;p&gt;That developer is rare. Most of the people coming through your sign-up flow don't know yet. They're evaluating. They showed up with a vague problem and a browser tab full of competitors. They're not looking for instructions. They're looking for a reason to stay.&lt;/p&gt;

&lt;p&gt;Your onboarding has no answer for that.&lt;/p&gt;

&lt;h2&gt;
  
  
  Signs Your Onboarding Is Optimized for the Wrong Developer
&lt;/h2&gt;

&lt;p&gt;Not all drop-off looks the same. Before we talk about what to fix, be honest about where you are. Check every statement that's true for your product right now.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your onboarding starts with "let's get you set up" rather than "here's what you'll be able to do"&lt;/li&gt;
&lt;li&gt;The getting-started guide assumes the developer has already chosen your product&lt;/li&gt;
&lt;li&gt;You have zero content in the first-run experience that explains why a developer should keep going&lt;/li&gt;
&lt;li&gt;Your quickstart requires credentials or configuration before showing value&lt;/li&gt;
&lt;li&gt;You can see where developers drop off in your funnel, but you don't know why&lt;/li&gt;
&lt;li&gt;Developers who ask questions in your Discord or Slack often say things like "I'm not sure if this is the right tool for me"&lt;/li&gt;
&lt;li&gt;Your product analytics show sign-ups climbing but first API calls staying flat&lt;/li&gt;
&lt;li&gt;You've improved documentation but seen no improvement in activation&lt;/li&gt;
&lt;li&gt;You've never watched a developer who doesn't know your product use it for the first time&lt;/li&gt;
&lt;li&gt;Most of your feedback comes from developers who made it through—not from the ones who left&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;If you checked 6 or more:&lt;/strong&gt; Your onboarding is designed for the committed developer. Everyone still evaluating you is walking into a wall.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you checked 3 to 5:&lt;/strong&gt; You've got a mixed experience. Some developers find what they need. Others don't, and they leave quietly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you checked 2 or fewer:&lt;/strong&gt; You're either genuinely strong here, or you haven't looked closely enough yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Real Problem: You're Starting the Conversation in the Middle
&lt;/h2&gt;

&lt;p&gt;Most dev tool founders assume that someone who signs up has made a decision. They haven't. Sign-up is curiosity, not commitment.&lt;/p&gt;

&lt;p&gt;When a developer lands in your product for the first time, here's their actual mental state: "I've heard of this. I have a problem that might fit. I have maybe 20 minutes to figure out if this is worth my time." They're not ready for your step-by-step quickstart. They're asking one question first: &lt;em&gt;Is this for me?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If your onboarding can't answer that question in the first two minutes, they leave. Not because they couldn't find the docs. Because they couldn't see themselves in your product.&lt;/p&gt;

&lt;p&gt;This is the assumption that kills activation: that showing people how to use your product is more important than showing them why they should. You've front-loaded instructions for a decision they haven't made yet.&lt;/p&gt;

&lt;p&gt;I see this constantly. Founders spend months refining the technical accuracy of their quickstart, and almost no time on the moment before it—the moment where a developer decides whether to read a single word of it.&lt;/p&gt;

&lt;p&gt;Once you lose that developer, they're gone. They're not coming back. They've already verified in their own mind that your product isn't what they need. You can try to pull them back with email sequences, but unless you know exactly why they left, you're guessing. And they already made up their mind.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to Fix (Starting This Week)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Build an onboarding fork for the evaluating developer
&lt;/h3&gt;

&lt;p&gt;The developer who knows why they're there needs a fast path to their first API call. The developer who's still deciding needs something different: proof that this is worth their time before they do a single technical step.&lt;/p&gt;

&lt;p&gt;Add a branch. At the start of your onboarding flow, let developers self-select: "I have a specific use case and I'm ready to build" vs. "I'm evaluating whether this is the right tool." The second path isn't a watered-down version of the first. It's a completely different experience—one designed to answer &lt;em&gt;Is this for me?&lt;/em&gt; before asking anything of the developer.&lt;/p&gt;

&lt;p&gt;This takes more work to build. It also directly addresses the moment where most of your drop-off is happening.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Move your value proof before your credential ask
&lt;/h3&gt;

&lt;p&gt;Count the steps in your current onboarding flow before a developer sees something working. Every step you ask of a developer before delivering proof of value is a step where they can leave.&lt;/p&gt;

&lt;p&gt;The goal is to invert the sequence. Value first, configuration second. If you can't show a developer what your product does without asking them to set things up first, figure out how to sandbox it. Interactive demos, pre-populated environments, example outputs they can explore before touching a single credential—any of these buys you trust before you ask for effort.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Add an activation question to your first-run experience
&lt;/h3&gt;

&lt;p&gt;Right now you're tracking behavior but not intent. You can see where developers drop off. You can't see what they were trying to do when they did.&lt;/p&gt;

&lt;p&gt;Add a single question early in the onboarding flow—not a survey, one question: "What are you trying to build?" or "What problem brought you here?" You don't need to use the answer to gate anything. You need it to understand which type of developer is coming through your door, and to make them feel seen. A developer who's asked what they're trying to accomplish feels like the product was made for them. That feeling matters more than most founders think.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Go watch a developer use your product for the first time
&lt;/h3&gt;

&lt;p&gt;Not someone on your team. Not someone in your network who's heard your pitch. Find a developer who matches your ICP but has never heard of you, and watch them use your product. Don't help. Don't explain. Just watch.&lt;/p&gt;

&lt;p&gt;You will see the exact moment they get confused, lose confidence, or stop believing the product is for them. That moment is your real drop-off problem. It's invisible in your funnel data and completely visible in a single session.&lt;/p&gt;

&lt;p&gt;Most founders avoid this because it's uncomfortable. It's also the single fastest way to understand what's actually happening between sign-up and activation.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Keep This From Recurring
&lt;/h2&gt;

&lt;p&gt;Fixing the immediate symptoms isn't enough. The underlying problem is that you have no ongoing signal from developers who didn't make it through. Your feedback loops are built around the people who survived your onboarding, which means they're systematically blind to the experience of everyone who didn't.&lt;/p&gt;

&lt;p&gt;Build a process to capture signal from the right population. That means:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Exit questions at drop-off points.&lt;/strong&gt; When a developer goes inactive in the first session without reaching activation, trigger a short question: "Was there something you were looking for that you couldn't find?" Not a survey. One question, low friction. Even a 5% response rate gives you patterns you don't have now.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Regular first-time user sessions.&lt;/strong&gt; Make it a recurring practice, not a one-off. Every six weeks, watch one developer who matches your ICP go through your onboarding cold. The patterns you see across sessions will tell you more about your activation problem than your analytics alone.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Track intent alongside behavior.&lt;/strong&gt; Your funnel shows you what developers did. Intent data—what they said they were trying to do—tells you why the behavior happened. Both are necessary. Right now most dev tool founders only have one of them.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Shortest Path to Answers
&lt;/h2&gt;

&lt;p&gt;If you want to understand your drop-off problem faster than any of this, there's one move that accelerates everything: get structured feedback from developers who match your ICP and have never heard of you.&lt;/p&gt;

&lt;p&gt;Not your current users. Not your network. Developers in the evaluation mindset—exactly the state of mind of the people leaving your product before their first API call.&lt;/p&gt;

&lt;p&gt;Everything above tells you what to fix. Unbiased evaluation sessions tell you which fixes matter most, in which order, for the specific developer segment you're losing.&lt;/p&gt;

&lt;p&gt;That's the sequence. Know who's leaving and why. Then fix it.&lt;/p&gt;

</description>
      <category>api</category>
      <category>tooling</category>
      <category>devrel</category>
    </item>
    <item>
      <title>Developer Journey Map: 5 Stages to Reduce Dev Churn</title>
      <dc:creator>Tessa Kriesel</dc:creator>
      <pubDate>Sat, 07 Mar 2026 00:54:00 +0000</pubDate>
      <link>https://dev.to/builtfordevs/developer-journey-map-5-stages-to-reduce-dev-churn-g4n</link>
      <guid>https://dev.to/builtfordevs/developer-journey-map-5-stages-to-reduce-dev-churn-g4n</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.unsplash.com%2Fphoto-1619468129361-605ebea04b44%3Fcrop%3Dentropy%26cs%3Dtinysrgb%26fit%3Dmax%26fm%3Djpg%26ixid%3DM3wxMTc3M3wwfDF8c2VhcmNofDF8fG1hcHxlbnwwfHx8fDE3NzI5MzEyNTN8MA%26ixlib%3Drb-4.1.0%26q%3D80%26w%3D2000" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.unsplash.com%2Fphoto-1619468129361-605ebea04b44%3Fcrop%3Dentropy%26cs%3Dtinysrgb%26fit%3Dmax%26fm%3Djpg%26ixid%3DM3wxMTc3M3wwfDF8c2VhcmNofDF8fG1hcHxlbnwwfHx8fDE3NzI5MzEyNTN8MA%26ixlib%3Drb-4.1.0%26q%3D80%26w%3D2000" alt="Developer Journey Map: 5 Stages to Reduce Dev Churn" width="2000" height="1333"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You've fixed your docs. Added a quickstart. Shipped features based on feedback. And retention is still flat.&lt;/p&gt;

&lt;p&gt;The problem isn't your product. It's where you stopped looking.&lt;/p&gt;

&lt;p&gt;Most teams treat Build like the finish line. They optimize the hell out of getting developers from sign-up to first API call, then wonder why those developers don't stick around. The developer journey has five stages—and if you're only investing in the middle ones, you're leaking developers at both ends without knowing it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Five Stages
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Discover&lt;/strong&gt; — First impression. Developers are barely paying attention yet. The only question they're asking: do you get me? If your messaging doesn't signal that immediately, they're gone before they ever consider you.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;What belongs here: website, inspiring content, social presence, developer referrals, community.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Evaluate&lt;/strong&gt; — Now they're deliberate. Comparing you to alternatives, checking pricing, looking for social proof. This is where most companies lose developers silently—no drop-off notification, no signal. They just move on.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;What belongs here: docs, quickstart guide, GitHub presence, pricing clarity, social proof.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Learn&lt;/strong&gt; — Hands-on testing. Time to first meaningful use matters here. So does confidence. The question isn't just "does this work?"—it's "can I make this work?" Developers who aren't sure they can succeed with your product won't stick around to find out.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;What belongs here: product access, tutorials, use case content, community where they can find answers fast.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Build&lt;/strong&gt; — They're executing. Speed to MVP matters. So does support when they get stuck. These are your highest-intent users—they've cleared every hurdle to get here. Treat them like it.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;What belongs here: reference guide, build shortcuts, changelog, responsive support.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scale&lt;/strong&gt; — This is where retained developers live. They're invested. They want to give feedback, influence your roadmap, and tell their peers. Developers are word-of-mouth marketing at the highest level of trust—but only if you've built something worth talking about at this stage. Most teams never do.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;What belongs here: case studies, beta programs, feedback and technical advisory board, developer partnerships.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Most Companies Actually Invest
&lt;/h2&gt;

&lt;p&gt;Evaluate, Learn, and maybe Build. That's it.&lt;/p&gt;

&lt;p&gt;Scale gets almost nothing. It's treated like a passive outcome—"if they stay, they stay." It's not. It requires the same active investment as every other stage. The developers who reach Scale are your most valuable asset. Ignoring them is one of the most expensive mistakes a dev tool company can make.&lt;/p&gt;

&lt;p&gt;Sound familiar?&lt;/p&gt;

&lt;h2&gt;
  
  
  The Real Problem: You Can't Fix What You Can't See
&lt;/h2&gt;

&lt;p&gt;Mapping the journey is step one. Measurement is where it gets real.&lt;/p&gt;

&lt;p&gt;Most teams know their sign-up rate. Almost none can tell you what's happening between stages—where developers are stalling, why they drop off, what's actually moving them forward.&lt;/p&gt;

&lt;p&gt;Without behavioral signal across all five stages, you're making product, content, and DevRel decisions based on incomplete information. You might be losing developers in Evaluate because your docs aren't trustworthy. Or in Scale because there's no community to plug into. You won't know until you look.&lt;/p&gt;

&lt;p&gt;The journey map isn't a one-time strategy exercise. It's a living measurement framework.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start Here
&lt;/h2&gt;

&lt;p&gt;For each of the five stages, answer three questions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What does the developer need to move forward?&lt;/li&gt;
&lt;li&gt;What do you have in place today?&lt;/li&gt;
&lt;li&gt;Where are the gaps?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You'll find them fast. The gaps in your Scale stage will probably surprise you.&lt;/p&gt;

&lt;p&gt;That's exactly what Built for Devs helps you do—map your developer journey, track behavioral signals across all five stages, and make decisions based on what's actually happening. &lt;a href="https://builtfor.dev/score?ref=blog.builtfor.dev" rel="noopener noreferrer"&gt;Get your free Developer Adoption Score&lt;/a&gt; and see where your gaps are today.&lt;/p&gt;

</description>
      <category>startup</category>
      <category>tooling</category>
      <category>devrel</category>
    </item>
    <item>
      <title>Feature Roadmaps Don't Drive Market Fit—Positive Experiences Do</title>
      <dc:creator>Tessa Kriesel</dc:creator>
      <pubDate>Sun, 01 Mar 2026 23:46:00 +0000</pubDate>
      <link>https://dev.to/builtfordevs/feature-roadmaps-dont-drive-market-fit-positive-experiences-do-24k6</link>
      <guid>https://dev.to/builtfordevs/feature-roadmaps-dont-drive-market-fit-positive-experiences-do-24k6</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.unsplash.com%2Fphoto-1498637841888-108c6b723fcb%3Fcrop%3Dentropy%26cs%3Dtinysrgb%26fit%3Dmax%26fm%3Djpg%26ixid%3DM3wxMTc3M3wwfDF8c2VhcmNofDJ8fHJvYWRtYXB8ZW58MHx8fHwxNzcyOTI3MjI5fDA%26ixlib%3Drb-4.1.0%26q%3D80%26w%3D2000" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.unsplash.com%2Fphoto-1498637841888-108c6b723fcb%3Fcrop%3Dentropy%26cs%3Dtinysrgb%26fit%3Dmax%26fm%3Djpg%26ixid%3DM3wxMTc3M3wwfDF8c2VhcmNofDJ8fHJvYWRtYXB8ZW58MHx8fHwxNzcyOTI3MjI5fDA%26ixlib%3Drb-4.1.0%26q%3D80%26w%3D2000" alt="Feature Roadmaps Don't Drive Market Fit—Positive Experiences Do" width="799" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Every founder obsesses over their feature roadmap. But the most successful dev tool founders I know—the ones who actually hit PMF—don't prioritize features at all. They prioritize the sequence of developer "aha moments." While you're debating whether to build that advanced dashboard or API versioning, they're mapping out the emotional journey that turns a skeptical developer into an advocate. The difference isn't what they build. It's when they reveal it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Feature Trap: Why Your Roadmap is Killing PMF
&lt;/h2&gt;

&lt;p&gt;Here's what happens in every dev tool Slack channel: "Users are asking for X feature." "Competitor Y just shipped Z." "Let's add it to the roadmap."&lt;/p&gt;

&lt;p&gt;Sound familiar?&lt;/p&gt;

&lt;p&gt;You're not alone. Most founders build their roadmap exactly this way—competitor analysis plus user requests equals priority. It feels logical. It feels data-driven.&lt;/p&gt;

&lt;p&gt;But here's the brutal truth: developers abandon your tool after signup not because you lack features, but because you're solving for the wrong moment in their journey.&lt;/p&gt;

&lt;p&gt;The problem is you're building for the developer who's already convinced your tool is worth their time. But that developer doesn't exist yet.&lt;/p&gt;

&lt;p&gt;Instead, you're facing a developer who's burned by broken promises, skeptical of new tools, and protective of their workflow. They've been hurt before. They don't trust you yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Hidden Cost of Feature-First Thinking
&lt;/h2&gt;

&lt;p&gt;Developers don't abandon tools because they lack features. They abandon tools because they can't figure out if those features actually solve their problem—and they give up trying.&lt;/p&gt;

&lt;p&gt;Think about the last dev tool you adopted. You didn't start by exploring every feature. You started with one specific pain point. You needed a quick win to justify spending more time. Only after that first success did you explore deeper functionality.&lt;/p&gt;

&lt;p&gt;But here's what most founders miss: developers need multiple small wins before they trust a new tool enough to integrate it into their actual workflow. Each win builds confidence. Each win reduces the perceived risk of adoption.&lt;/p&gt;

&lt;p&gt;The feature-first approach front-loads complexity. You're asking developers to evaluate your entire value proposition before they've experienced any value at all. That's cognitive overload, not product-market fit.&lt;/p&gt;

&lt;p&gt;The result? Developers sign up, get overwhelmed, and vanish. You blame it on onboarding or messaging. But the real issue is sequence—you're revealing your value in the wrong order.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Moment-First Framework: How PMF Winners Actually Build
&lt;/h2&gt;

&lt;p&gt;The founders who crack PMF think differently. They don't ask "What features should we build?" They ask "What sequence of moments will turn a skeptical developer into an advocate?"&lt;/p&gt;

&lt;p&gt;Here's their framework:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Map the emotional journey from skepticism to advocacy.&lt;/strong&gt;  Developers don't go from "never heard of you" to "integrated into my CI/CD pipeline" in one step. They move through predictable emotional states: Skeptical → Curious → Convinced → Trusting → Advocating.&lt;/p&gt;

&lt;p&gt;Your job isn't to build features. Your job is to design the moments that move developers through this progression.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Identify the sequence of small wins that build developer confidence.&lt;/strong&gt;  Every successful dev tool follows the same pattern: Quick Win → Trust Signal → Integration Moment.&lt;/p&gt;

&lt;p&gt;The Quick Win proves immediate value with minimal investment. It's the 'wow, this actually works' moment—the one that happens in under 5 minutes.&lt;/p&gt;

&lt;p&gt;The Trust Signal demonstrates the tool won't break their existing workflow. It's proof that your tool plays nicely with their stack, their team, their process.&lt;/p&gt;

&lt;p&gt;The Integration Moment is when they commit to using your tool in production. It's the point of no return—and it only happens after you've earned their trust.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sequence these moments deliberately.&lt;/strong&gt;  Most founders reveal everything at once. Winners reveal just enough to create the next moment. They hide complexity until developers are ready for it.&lt;/p&gt;

&lt;p&gt;This isn't about dumbing down your product. It's about respecting how developers actually adopt tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your 30-Day Moment Mapping Sprint
&lt;/h2&gt;

&lt;p&gt;Ready to stop building features and start building moments? Here's your implementation plan:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Week 1: Interview 10 developers about their tool adoption journey.&lt;/strong&gt;  Don't ask about your product. Ask about the last dev tool they adopted successfully—the one they actually use. What was their first interaction? When did they decide to keep using it? What almost made them quit?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Week 2: Map your current user flow against emotional states.&lt;/strong&gt;  Walk through your signup flow, onboarding, and first-use experience. At each step, ask: "What is the developer feeling right now? Skeptical? Confused? Confident?" Identify where you're creating friction instead of momentum.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Week 3: Identify your 3 core moments and sequence them.&lt;/strong&gt;  What's your Quick Win? What's your Trust Signal? What's your Integration Moment? Design each moment to build on the previous one. Hide everything else.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Week 4: Test the new flow with 5 developers.&lt;/strong&gt;  Watch them use your tool. Don't explain anything. Just observe. Are they experiencing the moments you designed? Where do they get stuck? Where do they light up?&lt;/p&gt;

&lt;p&gt;The founders who achieve PMF don't build better features. They build better moments. They understand that developers need emotional progression—not feature progression.&lt;/p&gt;

&lt;p&gt;Your roadmap shouldn't be a list of capabilities. It should be a sequence of experiences that transforms skeptics into advocates.&lt;/p&gt;

&lt;p&gt;Stop building features. Start building moments.&lt;/p&gt;

</description>
      <category>startup</category>
      <category>tooling</category>
      <category>devrel</category>
    </item>
    <item>
      <title>How I Used Claude Code's Multi-Agent Orchestration and Laravel to Rebuild a Backend Overnight</title>
      <dc:creator>Tessa Kriesel</dc:creator>
      <pubDate>Sun, 15 Feb 2026 19:24:31 +0000</pubDate>
      <link>https://dev.to/tessak22/how-i-used-claude-codes-multi-agent-orchestration-and-laravel-to-rebuild-a-backend-overnight-174</link>
      <guid>https://dev.to/tessak22/how-i-used-claude-codes-multi-agent-orchestration-and-laravel-to-rebuild-a-backend-overnight-174</guid>
      <description>&lt;p&gt;Last night at 8:50 PM, I sat down to rebuild a product's backend from scratch. By 11 PM, I had a complete Laravel API with auth, CRUD, real-time WebSockets, and chat. By 1:50 AM, the existing React Native frontend was wired up and running against it locally. Deployed to the cloud the next morning.&lt;/p&gt;

&lt;p&gt;That's about two hours for the entire backend. Five hours total including frontend integration.&lt;/p&gt;

&lt;p&gt;Here's how multi-agent orchestration, Laravel, and solid documentation made that possible.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Was Building
&lt;/h2&gt;

&lt;p&gt;The product is a real-time sports analytics platform. Live play-by-play, game scores, chat, coach dashboards, player profiles, the whole deal. The original product was built on a monolithic Python script with a FastAPI backend. It worked, but it wasn't built to scale.&lt;/p&gt;

&lt;p&gt;I decided to tear down the backend and rebuild it on Laravel. The existing React Native frontend just needed to be rewired to the new API. And I needed it done fast, because we're shipping in August.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Three-Tool Workflow
&lt;/h2&gt;

&lt;p&gt;I ended up using different Claude tools for different parts of the process. I'd done some research beforehand on how to work with Claude effectively, and the workflow that emerged was effective enough that I want to break it down.&lt;/p&gt;

&lt;p&gt;I used three:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Claude in the browser&lt;/strong&gt; for strategic planning. I fed it the CEO's product documentation, the existing codebase context, and our technical requirements. It generated a phased build plan, six phases covering everything from auth to deployment prep. This wasn't vague, it was specific enough to hand directly to Claude Code as prompts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Claude Code&lt;/strong&gt; for execution. Each phase of the build plan became a prompt. Claude Code scaffolded the Laravel backend phase by phase: migrations, models, controllers, API resources, broadcasting events, chat with profanity filtering, security hardening. Six phases in about two hours.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Multi-agent orchestration&lt;/strong&gt; for the messy middle. This is where it got interesting.&lt;/p&gt;

&lt;h2&gt;
  
  
  18 Agents Fixing Errors Simultaneously
&lt;/h2&gt;

&lt;p&gt;After the backend was built and the frontend was wired up, I had 175 TypeScript errors across 33 files. The old Python API returned flat objects with string IDs. The new Laravel API returned nested resources with integer IDs. Every screen that touched game data, team data, or player data was broken.&lt;/p&gt;

&lt;p&gt;Instead of fixing them one file at a time, I spun up multiple Claude Code agents in parallel. At one point, 18 agents were running simultaneously, each tackling a different batch of errors. One agent handled coach dashboard screens. Another fixed player stat field names. Another rewired the scores screens from flat fields to nested team objects.&lt;/p&gt;

&lt;p&gt;They all worked against the same codebase without stepping on each other, because each agent had a scoped task. The errors went from 175 to 0 across eight batches.&lt;/p&gt;

&lt;p&gt;That kind of parallelism just isn't possible with a single-threaded workflow, human or AI.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Laravel Was the Cheat Code
&lt;/h2&gt;

&lt;p&gt;The original backend was a monolithic Python script. One file doing everything. Translating that into Laravel was almost unfairly easy.&lt;/p&gt;

&lt;p&gt;Laravel gives you so much out of the box. Sanctum for API auth with token management. Eloquent for database models with relationships. API Resources for consistent JSON response shaping. Broadcasting with Reverb for WebSockets. Built-in rate limiting, validation, and middleware. Even the profanity filter for chat was straightforward with Laravel's pipeline pattern.&lt;/p&gt;

&lt;p&gt;What would've been weeks of custom plumbing in the old stack became &lt;code&gt;php artisan make:model&lt;/code&gt;, define relationships, write a resource class, done. The CRUD patterns practically wrote themselves, and Claude Code was incredibly effective at generating Laravel code because the framework's conventions are so well-defined.&lt;/p&gt;

&lt;p&gt;Six phases. Two and a half hours. A complete API with auth, CRUD, game stats, play-by-play engine, real-time broadcasting, chat, and deployment prep.&lt;/p&gt;

&lt;h2&gt;
  
  
  Documentation Made the AI Work
&lt;/h2&gt;

&lt;p&gt;The reason Claude's build plan was so accurate on the first pass? The founder's documentation was thorough.&lt;/p&gt;

&lt;p&gt;The founder had detailed specs for every feature. Field definitions for game data. User role descriptions. Chat behavior rules. Stat categories and how they should be grouped. When I fed that into Claude in the browser alongside the existing codebase, the AI had enough context to generate a build plan that actually mapped to reality.&lt;/p&gt;

&lt;p&gt;Garbage in, garbage out applies to AI workflows too. If the product documentation had been vague, I'd have spent half my time clarifying requirements instead of building.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Full Timeline
&lt;/h2&gt;

&lt;p&gt;Here's how the night actually went:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Time&lt;/th&gt;
&lt;th&gt;What Happened&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;8:50 PM&lt;/td&gt;
&lt;td&gt;Created the Laravel project, started Phase 1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9:32 PM&lt;/td&gt;
&lt;td&gt;Auth system complete (Sanctum, login, register, roles)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10:00 PM&lt;/td&gt;
&lt;td&gt;Core CRUD, search, dashboard, coach notes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10:15 PM&lt;/td&gt;
&lt;td&gt;Game stats engine, play-by-play, data export&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10:31 PM&lt;/td&gt;
&lt;td&gt;Real-time broadcasting, chat, profanity filter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10:54 PM&lt;/td&gt;
&lt;td&gt;Security hardening, error tracking, deployment prep&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;11:00 PM&lt;/td&gt;
&lt;td&gt;Backend done. Six phases in ~2 hours.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;11:42 AM&lt;/td&gt;
&lt;td&gt;Brought in Claude Code for frontend integration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1:50 AM&lt;/td&gt;
&lt;td&gt;Frontend wired to backend, full stack running locally&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Next morning&lt;/td&gt;
&lt;td&gt;Deployed backend to Laravel Cloud, frontend to Vercel&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Push-to-deploy on both platforms. The team could pull up the app on their phones by the time church was over.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'd Tell Other Developers
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Use AI at every layer, but different AI for each layer.&lt;/strong&gt; Browser-based Claude is great for planning and strategy. Claude Code is great for execution. Multi-agent orchestration is great for parallel problem-solving. Don't try to do everything in one tool.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pick a framework with strong conventions.&lt;/strong&gt; Laravel's opinionated structure made it trivially easy for Claude Code to generate correct, idiomatic code. The more predictable your framework, the more effective AI-assisted development becomes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Invest in documentation before you start building.&lt;/strong&gt; The single biggest accelerator wasn't the AI itself, it was the quality of the input. Thorough product docs meant the build plan was right on the first try. No back-and-forth. No "actually, I meant this."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Let the agents scope themselves.&lt;/strong&gt; When I ran 18 agents simultaneously, Claude Code broke the work into batches on its own, each agent handling a specific set of files and error types. They didn't overlap. I didn't have to manually assign work, I just pointed it at the problem and it parallelized the fix.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Don't be afraid of ambitious timelines.&lt;/strong&gt; A complete backend rebuild in one night sounds absurd. But with the right tools, the right framework, and solid documentation, it's just a series of well-scoped tasks executed in parallel. The ceiling on what one developer can ship in a session has fundamentally changed.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;I'm Tessa Kriesel, CEO of &lt;a href="https://www.builtfor.dev/" rel="noopener noreferrer"&gt;Built for Devs&lt;/a&gt; and part-time CTO at a startup. By day I help developer tools with product adoption and go-to-market. By night, apparently, I rebuild backends with 18 AI agents running at once. Find me online if you want to talk developer products or multi-agent orchestration.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>ai</category>
      <category>productivity</category>
      <category>learning</category>
    </item>
    <item>
      <title>Why the Next AWS Outage Will Cost You More Than the Last One (And What to Do About It)</title>
      <dc:creator>Tessa Kriesel</dc:creator>
      <pubDate>Thu, 05 Feb 2026 23:08:37 +0000</pubDate>
      <link>https://dev.to/controlplane/why-the-next-aws-outage-will-cost-you-more-than-the-last-one-and-what-to-do-about-it-508j</link>
      <guid>https://dev.to/controlplane/why-the-next-aws-outage-will-cost-you-more-than-the-last-one-and-what-to-do-about-it-508j</guid>
      <description>&lt;p&gt;When AWS US-EAST-1 went dark on October 20, 2025, over 3,500 companies across 60 countries went down with it.&lt;/p&gt;

&lt;p&gt;Not because their code was broken. Because their architecture was.&lt;/p&gt;

&lt;p&gt;Here's what happened: a race condition in DynamoDB's DNS management system triggered a cascade that took down everything depending on it. Auth services. Routing layers. Even companies running in &lt;em&gt;other&lt;/em&gt; AWS regions discovered their "multi-region" setups had hidden dependencies on US-EAST-1.&lt;/p&gt;

&lt;p&gt;If you watched that unfold from your incident Slack channel, you already know 100% uptime is a myth. The real question isn't whether your infrastructure will fail. It's whether your architecture keeps serving traffic while the hyperscaler figures it out.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Spoiler: most architectures don't.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;The Math Nobody Wants to Talk About&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Availability is a simple ratio:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Availability = MTBF / (MTBF + MTTR)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Most engineering teams obsess over MTBF (how do we prevent failures?). That's the wrong question. The October outage lasted &lt;strong&gt;15 hours&lt;/strong&gt;. AWS's own SLA guarantees 99.99% for most services, which allows roughly 52 minutes of downtime &lt;em&gt;per year&lt;/em&gt;. Fifteen hours blew past that in a single incident.&lt;/p&gt;

&lt;p&gt;For large enterprises, unplanned downtime now costs an average of $2 million per hour. Not because servers are expensive. Because revenue stops, customer trust erodes, and under regulations like DORA (fully implemented in 2025), financial institutions face actual penalties for failing to demonstrate resilience by design.&lt;/p&gt;

&lt;p&gt;Here's what the nines actually look like in practice:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Availability&lt;/th&gt;
&lt;th&gt;Annual Downtime&lt;/th&gt;
&lt;th&gt;What It Actually Takes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;99.9% (three nines)&lt;/td&gt;
&lt;td&gt;8.45 hours&lt;/td&gt;
&lt;td&gt;Single cloud, good ops team&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;99.99% (four nines)&lt;/td&gt;
&lt;td&gt;52.56 minutes&lt;/td&gt;
&lt;td&gt;Redundancy within one provider&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;99.999% (five nines)&lt;/td&gt;
&lt;td&gt;5.26 minutes&lt;/td&gt;
&lt;td&gt;Cross-cloud failover, zero single points of failure&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;See the jump from four nines to five? That's not a 25% improvement in ops discipline. That's a fundamentally different architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;You've Already Crossed the Complexity Horizon&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Your backend isn't complicated like a jet engine where cause and effect are linear. It's complex like a biological system.&lt;/p&gt;

&lt;p&gt;A DNS hiccup triggers aggressive retry loops across thousands of microservices. That saturates your database connection pool. Your load balancer marks an entire region as down. One small thing breaks, and suddenly everything breaks in ways nobody predicted.&lt;/p&gt;

&lt;p&gt;Systems theorists call this the Complexity Horizon: the point where interdependencies are so dense that cascading failure isn't a risk to mitigate. It's a mathematical certainty to plan for.&lt;/p&gt;

&lt;p&gt;Three patterns made the October outage as devastating as it was. Sound familiar?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Thundering Herd.&lt;/strong&gt; A core service hiccupped. Thousands of client applications entered aggressive retry loops simultaneously, creating a self-inflicted DDoS that prevented the system from ever stabilizing. The fix couldn't deploy because the problem kept feeding itself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The IAM Lockout.&lt;/strong&gt; The engineers who needed to fix the problem couldn't authenticate to their own systems. Why? The identity layer was part of the failure chain. The people with the keys were locked outside with everyone else.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Monoculture Risk.&lt;/strong&gt; Three providers control 63% of global cloud infrastructure. A power issue in one Virginia data center cascaded into a global economic disruption in minutes. Virginia. One state. Global impact.&lt;/p&gt;

&lt;p&gt;Every one of these patterns stems from the same root cause: deep dependency on a single provider's infrastructure stack.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;The Real Decision Most Teams Are Avoiding&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;After every major outage, the playbook is the same. Better monitoring. Tighter runbooks. More chaos engineering.&lt;/p&gt;

&lt;p&gt;Those are all fine. But here's the problem—they're optimizations within the same architecture that just failed you.&lt;/p&gt;

&lt;p&gt;The real decision is structural: &lt;strong&gt;Do you keep bolting resilience onto a single-cloud foundation, or do you put an orchestration layer between your code and the infrastructure?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let me explain myself.&lt;/p&gt;

&lt;p&gt;This is the same evolution that played out with email. There was a time when every company employed Exchange Server engineers (at least two, because if one was out, you needed redundancy). Email was a solved problem being re-solved by every organization individually. At enormous cost.&lt;/p&gt;

&lt;p&gt;Then Google and Microsoft offered email as a service. You paid by the mailbox and never thought about it again. The Exchange Server engineers didn't disappear. The good ones moved up the stack to work on problems that actually differentiated their business.&lt;/p&gt;

&lt;p&gt;Cloud infrastructure is at that exact inflection point right now.&lt;/p&gt;

&lt;p&gt;Every company delivering digital services is hiring platform engineering teams to stitch together the same backend concerns: secrets management, service discovery, mutual TLS, geo-routing, logging, metrics, tracing, observability. The cloud gives you building blocks (Kubernetes as a service, object storage, managed databases), but the integration work between those primitives and production-ready software? That's on you. Every single time.&lt;/p&gt;

&lt;p&gt;That's a massive amount of duplicated effort across the entire industry. And it's the reason most organizations can't get past four nines. They're spending all their engineering budget rebuilding the same plumbing instead of investing in the architecture that would actually change the math.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Here's What Actually Changes the Math&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Getting to five nines (5.26 minutes of downtime per year) requires three things that are nearly impossible when you're locked into a single cloud provider:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Instant cross-cloud failover.&lt;/strong&gt; When AWS goes down, your workloads need to be serving from GCP or Azure within seconds. Not hours. Not "we'll spin up a DR environment." Actually serving production traffic from another provider without missing a beat. That's what turns a 15-hour outage into a non-event for your customers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Zero hidden single points of failure.&lt;/strong&gt; Your identity layer. Your DNS. Your routing. None of it can depend on the provider that's currently on fire. This requires a genuine abstraction layer, not just multi-region deployments that secretly phone home to a single control plane.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Portability without rearchitecting.&lt;/strong&gt; If moving off a provider requires months of engineering work, you don't have resilience. You have a very expensive backup plan you'll never actually execute under pressure.&lt;/p&gt;

&lt;p&gt;This is the problem Control Plane was built to solve.&lt;/p&gt;

&lt;p&gt;The platform provides a single orchestration layer across AWS, Azure, GCP, Oracle, and on-prem infrastructure. Your code deploys once and runs anywhere. When a provider goes down, traffic shifts automatically: no manual intervention, no runbooks, no 3 AM pages.&lt;/p&gt;

&lt;p&gt;We call it the non-stick layer. Your workloads aren't welded to any single provider, so the cost of moving—for resilience, cost optimization, or avoiding lock-in—drops to near zero.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;The Part Your CFO Will Actually Care About&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Resilience alone is a hard budget conversation. "Spend more money so that when something bad happens, it's less bad" is a tough sell. I get it.&lt;/p&gt;

&lt;p&gt;But here's what most teams miss: the architecture that delivers five-nines resilience also fundamentally changes your cost structure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You stop paying for idle compute.&lt;/strong&gt; Traditional cloud billing charges you for full VMs whether you're using 100% of the CPU or 3%. Control Plane bills in millicores (thousandths of a vCPU). You pay for the actual compute your workload consumes, not the full machine sitting there mostly idle. Customers see 40-60% savings on cloud compute. That's real money.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You get reserved instance pricing without the commitment.&lt;/strong&gt; Instead of locking into a three-year contract to get a reasonable per-core rate, Control Plane offers on-demand pricing lower than what most providers charge for reserved instances. No commitment. Fractional billing. The math just works.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You shrink or redeploy your platform engineering team.&lt;/strong&gt; The median platform engineer costs $180-220K fully loaded. Most mid-size companies employ 4-10 of them to maintain the backend plumbing that Control Plane provides out of the box. That's $700K to $2.2M per year in labor spent re-solving solved problems. Before you even factor in the opportunity cost of what those engineers could be building instead.&lt;/p&gt;

&lt;p&gt;Add it up: lower compute costs, no lock-in premiums, and a platform engineering team that can finally work on the product instead of the plumbing.&lt;/p&gt;

&lt;p&gt;The resilience is almost a bonus.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;What You Should Actually Do Next&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The October outage wasn't an anomaly. It was a preview. As AI workloads grow and backend complexity increases, the cascades will get worse. Here's how to get ahead of the next one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Accept that outages are inevitable and design for recovery speed.&lt;/strong&gt; Your competitive advantage isn't preventing failures. It's your Resilience Velocity—how fast your architecture recovers without human intervention. Invest in automated failover, not bigger ops teams.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Eliminate monoculture risk at the architecture level.&lt;/strong&gt; Multi-region isn't multi-cloud. If your "redundancy" strategy lives entirely within one provider's ecosystem, you're diversified in geography but not in risk. True resilience means your workloads can run on any provider and switch between them automatically.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stop rebuilding solved infrastructure.&lt;/strong&gt; Every month your platform team spends maintaining secrets management, service mesh, and observability tooling is a month they're not spending on the product your customers are paying for. The same pattern that moved email from on-prem Exchange to managed services is coming for backend infrastructure. The companies that make that shift early will ship faster, spend less, and sleep better.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Audit your hidden dependencies.&lt;/strong&gt; After October, dozens of companies discovered their "multi-cloud" setups had hidden dependencies on US-EAST-1 for auth or routing. Map every service your infrastructure depends on and ask: if this goes down, do we go down with it?&lt;/p&gt;

&lt;p&gt;The Complexity Horizon isn't something you overcome. It's something you architect around.&lt;/p&gt;

&lt;p&gt;The companies that weathered October without a scratch weren't the ones with the biggest ops teams. They were the ones whose architecture made the provider outage irrelevant.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Control Plane delivers production-grade backend infrastructure across every major cloud provider, with automatic cross-cloud failover, fractional compute billing, and built-in secrets management, service mesh, and observability.&lt;/em&gt; &lt;a href="https://dub.sh/cp-docs" rel="noopener noreferrer"&gt;&lt;em&gt;See how it works →&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>cloud</category>
      <category>productivity</category>
      <category>architecture</category>
      <category>kubernetes</category>
    </item>
  </channel>
</rss>
