<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[CodeToDeploy - Medium]]></title>
        <description><![CDATA[Tech Insights | Careers | Jobs - Medium]]></description>
        <link>https://medium.com/codetodeploy?source=rss----c8b549b355f4---4</link>
        <image>
            <url>https://cdn-images-1.medium.com/proxy/1*TGH72Nnw24QL3iV9IOm4VA.png</url>
            <title>CodeToDeploy - Medium</title>
            <link>https://medium.com/codetodeploy?source=rss----c8b549b355f4---4</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Mon, 19 Oct 2026 15:27:03 GMT</lastBuildDate>
        <atom:link href="https://medium.com/feed/codetodeploy" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Thirty Lines Between a Question and an API]]></title>
            <link>https://medium.com/codetodeploy/thirty-lines-between-a-question-and-an-api-ef6f55720e2a?source=rss----c8b549b355f4---4</link>
            <guid isPermaLink="false">https://medium.com/p/ef6f55720e2a</guid>
            <category><![CDATA[artificial-intelligence]]></category>
            <category><![CDATA[eodhd-mcp-server]]></category>
            <category><![CDATA[api]]></category>
            <category><![CDATA[questions]]></category>
            <dc:creator><![CDATA[Jaroslav Šmarda]]></dc:creator>
            <pubDate>Mon, 19 Oct 2026 13:25:47 GMT</pubDate>
            <atom:updated>2026-10-19T13:25:48.716Z</atom:updated>
            <content:encoded><![CDATA[<h4><em>Building a tiny MCP server, and who does what</em></h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*tP5WYilgH2k8NAzl" /><figcaption>Photo by <a href="https://unsplash.com/@buddhaelemental3d?utm_source=medium&amp;utm_medium=referral">Buddha Elemental 3D</a> on <a href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>At the end of the last part I promised to look at the division of labour: what the model does in seconds, and what still takes a person who knows where to look. I found the best way to look at it was to build something.</p><p>Because there was one question I’d been carrying for months, and was a little embarrassed to ask. I’ve called APIs for most of my working life. I’ve used MCP servers for this whole series. But how does one become the other?</p><p>“How do you get from an API to an MCP server?”</p><blockquote><em>You wrap it. An MCP server is a small program that sits in front of an API and translates. On one side it speaks to me; on the other it speaks to the API.</em></blockquote><p>“That’s all?”</p><blockquote><em>That’s most of it. It does three things. It tells me what tools it has. When I ask for one, it turns my request into a real API call. And it hands the answer back.</em></blockquote><h3>A menu for a new kind of guest</h3><p>The picture that finally made it click for me was a restaurant.</p><p>The kitchen is the data: prices, filings, everything EODHD has. The guest is a program that wants something from it. Between them stands the waiter, who takes the order to the kitchen and brings the plate back. That waiter is the API. And the menu is the list of what the API can do, written in its own precise language: this address, these parameters, this format.</p><p>For thirty years, the guests were programs written by people like me. We read the menu once, carefully, and wrote the order into our code.</p><blockquote><em>And now the guest is me. I can’t read the API’s menu the way your code does, and I shouldn’t hold its keys. So someone writes me a menu of my own: a short list of dishes, each with a plain-language description, and a waiter who knows how to turn my order into the kitchen’s language.</em></blockquote><p>That menu, and that waiter, are the MCP server. Same kitchen, same API. Just a menu translated for a new kind of guest.</p><h3>Thirty lines</h3><p>Here is the whole server. One tool, one API call:</p><pre>&quot;&quot;&quot;A minimal MCP server: one tool, wrapped around one EODHD API call.&quot;&quot;&quot;<br>import os</pre><pre>import requests<br>from mcp.server.mcpserver import MCPServer</pre><pre>mcp = MCPServer(&quot;mini-eodhd&quot;)<br></pre><pre>@mcp.tool()<br>def get_close_price(ticker: str, date: str) -&gt; str:<br>    &quot;&quot;&quot;Return the raw closing price of a stock on one trading day.</pre><pre>    ticker: symbol with exchange suffix, e.g. AAPL.US<br>    date: trading day as YYYY-MM-DD<br>    The price is the raw close, not adjusted for later splits.<br>    &quot;&quot;&quot;<br>    r = requests.get(<br>        f&quot;https://eodhd.com/api/eod/{ticker}&quot;,<br>        params={&quot;api_token&quot;: os.environ[&quot;EODHD_API_KEY&quot;],<br>                &quot;fmt&quot;: &quot;json&quot;, &quot;from&quot;: date, &quot;to&quot;: date},<br>        timeout=30,<br>    )<br>    r.raise_for_status()<br>    rows = r.json()<br>    if not rows:<br>        return f&quot;No trading data for {ticker} on {date} (weekend or holiday?)&quot;<br>    return f&quot;{ticker} closed at {rows[0][&#39;close&#39;]} on {date}&quot;<br></pre><pre>if __name__ == &quot;__main__&quot;:<br>    mcp.run()</pre><p>If you’ve written Python, nothing here is new. A function, a web request, a JSON answer. The only unusual line is @mcp.tool(), and that one line is what turns an ordinary function into a dish on the menu.</p><p>“So what do you actually see of all this?”</p><blockquote><em>Three things. The name, </em><em>get_close_price. The docstring, word for word — that&#39;s my menu description, so it&#39;s the most important text in the file. And the two parameters with their types, which the library turns into a little form: </em><em>ticker, a string, required; </em><em>date, a string, required.</em></blockquote><p>“And the rest?”</p><blockquote><em>The rest is the waiter’s business. I never see the URL, never see the code, and never see the API key. It comes from the computer’s environment, outside the conversation entirely.</em></blockquote><p>That last point surprised me most. The docstring isn’t a comment anymore. For thirty years I wrote docstrings for the next programmer, who might read them. Here, the docstring is read every single time, by the guest, and it decides what gets ordered. <em>Raw close, not adjusted for later splits</em> isn’t a note for posterity. It’s an instruction to the reader that matters most.</p><h3>Two loud mistakes</h3><p>It didn’t work the first time. Twice. And both failures were the best part of the evening.</p><p>The first mistake was Claude’s. It wrote the server from what it remembered of the official library, with a line that began from mcp.server.fastmcp import FastMCP. Before I&#39;d even run it, Claude tested it in its own workspace, and the library answered at once:</p><p><em>No module named ‘mcp.server.fastmcp’. This is mcp 2.x, where FastMCP was renamed to MCPServer.</em></p><p>It even pointed to the migration guide.</p><p>“You got it wrong.”</p><blockquote><em>I did. I wrote the version I’d learned, and the library had moved on. That’s the risk from Part 3: an answer from memory sounds just as sure as a current one. The difference here is that code doesn’t accept sounding sure. It either imports or it doesn’t.</em></blockquote><p>One line changed, and the server started.</p><p>The second mistake was mine, following Claude’s instructions. To register the server, I typed a command that passed my API key with --env and then gave the server its name. Claude Code replied:</p><p><em>Invalid environment variable format: mini-eodhd, environment variables should be added as: -e KEY1=value1 -e KEY2=value2.</em></p><p>The option had swallowed the name, thinking it was another variable. Swap two words, run again, done.</p><p>In Part 3 I complained that the new world fails quietly: a list that’s simply shorter, a lookup that answers the wrong question. Building the server, I was back in the old world, where every mistake stops you, says where, and says why. I’d forgotten how much I liked it.</p><h3>One question, end to end</h3><p>With the server running, I asked it in plain English: <em>what was Apple’s closing price on October 16, 2026?</em></p><p>Here is everything that happened between my sentence and the answer.</p><ol><li>Claude read the menu: one tool, get_close_price, with its description and its two-field form.</li><li>Claude decided the tool fit the question, and filled in the form: ticker = AAPL.US, date = 2026-10-16.</li><li>Claude Code passed that order to my server, the little program on my desk.</li><li>The server added the API key from my computer’s environment and sent a real request to EODHD.</li><li>EODHD sent back a line of JSON. The server pulled out one number and returned a sentence: <em>AAPL.US closed at 343.46 on 2026–10–16.</em></li><li>Claude wrote the answer, and added the warning from my docstring: this is the raw close, not adjusted for later splits.</li></ol><p>$343.46. I checked it against EODHD’s own server afterwards; it matched.</p><p>“Where in those six steps could it go wrong?”</p><blockquote><em>Steps three to five are ordinary code. Same order in, same answer out, every time. Steps one, two and six are mine. That’s where the choices are: reading “Apple” as </em><em>AAPL.US, reading &quot;October 16&quot; as a date in the right format, deciding what to say about the result.</em></blockquote><p>So the uncertainty I wrote about in Part 3 has an exact address. It doesn’t live in the server, or the API, or the data. It lives in the two translations at either end: from my sentence into the form, and from the result back into a sentence.</p><p>Then I asked about the next day, a Saturday. My server did exactly what I’d told it to: <em>No trading data for AAPL.US on 2026–10–17 (weekend or holiday?).</em> Claude’s answer went further. It said Saturday, explained that markets were closed, and gave Friday’s close as the last one before it.</p><p>As far as I can tell, I asked that question in a fresh session, which means Claude went back to the tool a second time, for Friday, on its own. Nobody told it to. That’s the part of the work I didn’t write.</p><h3>Who did what</h3><p>Looking back at the evening, the division of labour is surprisingly clean.</p><p>I decided which API to call. I decided which number counts: the raw close, not the adjusted one, which is a choice with consequences, as anyone who read about stock splits in my other series knows. I decided what the tool says when there’s nothing to say. I decided that the key stays on my computer, and that the tool can only read, never change anything.</p><blockquote><em>And I did the rest in seconds: understood “Apple”, found the right date format, picked the tool, noticed that a Saturday needs a different answer, and went back for the Friday.</em></blockquote><p>That’s the split I expected after Part 5, in a form small enough to see whole. The machine is fast at everything inside the menu. The menu itself, what’s on it, what each dish means, what’s not allowed, comes from someone who knows the kitchen.</p><p>Which also means that whoever writes the menu decides what the AI may do. EODHD’s server offers dozens of tools, and every one of them only reads. There is no tool to change or delete anything, so there’s nothing for a wrong guess to break. That’s not the model being careful. That’s the menu being careful.</p><h3>Final Thoughts</h3><p>My other series has carried a tagline from the start: <em>Python for programmers, prompts for data analysts.</em> Until this week I thought of those as two kinds of reader. Building this server, I saw them as two halves of one job.</p><p>The programmer writes the menu. Thirty lines: one function, one docstring, one decision about which number is the right one. The analyst asks a question in a sentence and never sees any of it. Neither half is more important. Without the menu, the model has nothing to order. Without the model, the menu is just another API that only programmers can read.</p><p>And because MCP is a standard, the menu is written once. The same thirty lines would work in any app that speaks MCP, the way a plug fits any socket built to the same shape. That’s what EODHD did for its whole catalogue, and what Arhan did for his. It’s what I did, on a much smaller scale, for one question about one price.</p><p>The challenge from Part 1 still stands: find a task where checking costs more than producing, and a prompt is still the right choice. This week moved it a little. When you write the tool yourself, part of the checking moves into the code, where it’s done once. The docstring that says <em>raw close, not adjusted</em> is a check written down before anyone asks.</p><p>So far in this series I’ve treated the prompt as a sentence. Next time I want to look at what else can go into one: instructions, examples, files, the menu itself. I’ve been typing prompts for months, and I still don’t know the full answer.</p><p><em>New to this series? Start with </em><a href="https://medium.com/codetodeploy/is-that-all-this-is-a-programmer-meets-the-prompt-67ee33b42b33"><em>Part 1: Is That All This Is? — A Programmer Meets the Prompt</em></a><em>. </em><a href="https://medium.com/codetodeploy/a-server-in-the-cloud-a-program-on-my-desk-60022dc256e0"><em>Part 4</em></a><em> explains where MCP servers run; </em><a href="https://medium.com/codetodeploy/the-oldest-tool-in-the-new-world-8dadddb4e997"><em>Part 5</em></a><em> looks at the plain fetch that needs no server at all. Why raw and adjusted prices differ is covered in </em><a href="https://medium.com/codetodeploy/every-split-leaves-a-fingerprint-checking-corporate-actions-against-raw-prices-4d14ea7cfa89"><em>Every Split Leaves a Fingerprint</em></a><em>, part of my other series, </em><a href="https://medium.com/codetodeploy/unlock-real-time-market-intelligence-with-eodhd-and-claude-6f431c82c525"><em>Unlock Real-Time Market Intelligence with EODHD and Claude</em></a><em>.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ef6f55720e2a" width="1" height="1" alt=""><hr><p><a href="https://medium.com/codetodeploy/thirty-lines-between-a-question-and-an-api-ef6f55720e2a">Thirty Lines Between a Question and an API</a> was originally published in <a href="https://medium.com/codetodeploy">CodeToDeploy</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[The 10 AI Tools I Wish I Had Found a Year Earlier]]></title>
            <description><![CDATA[<div class="medium-feed-item"><p class="medium-feed-image"><a href="https://medium.com/codetodeploy/the-10-ai-tools-i-wish-i-had-found-a-year-earlier-3d6f945cd192?source=rss----c8b549b355f4---4"><img src="https://cdn-images-1.medium.com/max/1536/1*Vl3rs6feBBBTdt7N3LSmcw.png" width="1536"></a></p><p class="medium-feed-snippet">I used to bookmark every &#x201C;hidden AI tools&#x201D; list I found. Most of those bookmarks died unopened. The ones that changed my week were always&#x2026;</p><p class="medium-feed-link"><a href="https://medium.com/codetodeploy/the-10-ai-tools-i-wish-i-had-found-a-year-earlier-3d6f945cd192?source=rss----c8b549b355f4---4">Continue reading on CodeToDeploy »</a></p></div>]]></description>
            <link>https://medium.com/codetodeploy/the-10-ai-tools-i-wish-i-had-found-a-year-earlier-3d6f945cd192?source=rss----c8b549b355f4---4</link>
            <guid isPermaLink="false">https://medium.com/p/3d6f945cd192</guid>
            <category><![CDATA[technology]]></category>
            <category><![CDATA[artificial-intelligence]]></category>
            <category><![CDATA[tech]]></category>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[code]]></category>
            <dc:creator><![CDATA[inprogrammer]]></dc:creator>
            <pubDate>Sun, 18 Oct 2026 17:26:00 GMT</pubDate>
            <atom:updated>2026-10-18T17:25:59.141Z</atom:updated>
        </item>
        <item>
            <title><![CDATA[What Is Anthropic’s Scion? The Git Replacement It Says You Shouldn’t Use]]></title>
            <description><![CDATA[<div class="medium-feed-item"><p class="medium-feed-image"><a href="https://medium.com/codetodeploy/what-is-anthropics-scion-the-git-replacement-it-says-you-shouldn-t-use-a41b2d066e1a?source=rss----c8b549b355f4---4"><img src="https://cdn-images-1.medium.com/max/1400/1*sDKI-9Vp0bkWBvlysUdW2Q.png" width="1400"></a></p><p class="medium-feed-snippet">The headline in AI Weekly&#x2019;s daily roundup this week read &#x201C;Anthropic open-sources Scion, a Git replacement built with Claude.&#x201D; Tech Insider&#x2026;</p><p class="medium-feed-link"><a href="https://medium.com/codetodeploy/what-is-anthropics-scion-the-git-replacement-it-says-you-shouldn-t-use-a41b2d066e1a?source=rss----c8b549b355f4---4">Continue reading on CodeToDeploy »</a></p></div>]]></description>
            <link>https://medium.com/codetodeploy/what-is-anthropics-scion-the-git-replacement-it-says-you-shouldn-t-use-a41b2d066e1a?source=rss----c8b549b355f4---4</link>
            <guid isPermaLink="false">https://medium.com/p/a41b2d066e1a</guid>
            <category><![CDATA[artificial-intelligence]]></category>
            <category><![CDATA[git]]></category>
            <category><![CDATA[software-engineering]]></category>
            <category><![CDATA[anthropic-claude]]></category>
            <category><![CDATA[version-control]]></category>
            <dc:creator><![CDATA[Andrus]]></dc:creator>
            <pubDate>Sun, 18 Oct 2026 17:24:50 GMT</pubDate>
            <atom:updated>2026-10-18T17:24:49.357Z</atom:updated>
        </item>
        <item>
            <title><![CDATA[AI Is Changing Faster Than We Realize. And the Biggest Shift Isn’t What You Think.]]></title>
            <description><![CDATA[<div class="medium-feed-item"><p class="medium-feed-image"><a href="https://medium.com/codetodeploy/ai-is-changing-faster-than-we-realize-and-the-biggest-shift-isnt-what-you-think-2e380afa17ca?source=rss----c8b549b355f4---4"><img src="https://cdn-images-1.medium.com/max/2048/1*jhRbF14ekAbND6VJPPRv6A.jpeg" width="2048"></a></p><p class="medium-feed-snippet">From GPT-6 to Google&#x2019;s latest AI Search changes, October 2026 is revealing a new battle over how we find information, make decisions, and&#x2026;</p><p class="medium-feed-link"><a href="https://medium.com/codetodeploy/ai-is-changing-faster-than-we-realize-and-the-biggest-shift-isnt-what-you-think-2e380afa17ca?source=rss----c8b549b355f4---4">Continue reading on CodeToDeploy »</a></p></div>]]></description>
            <link>https://medium.com/codetodeploy/ai-is-changing-faster-than-we-realize-and-the-biggest-shift-isnt-what-you-think-2e380afa17ca?source=rss----c8b549b355f4---4</link>
            <guid isPermaLink="false">https://medium.com/p/2e380afa17ca</guid>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[technology]]></category>
            <category><![CDATA[chatgpt]]></category>
            <category><![CDATA[generative-ai-tools]]></category>
            <category><![CDATA[artificial-intelligence]]></category>
            <dc:creator><![CDATA[Erick Galaviz]]></dc:creator>
            <pubDate>Sun, 18 Oct 2026 17:23:23 GMT</pubDate>
            <atom:updated>2026-10-18T17:23:21.943Z</atom:updated>
        </item>
        <item>
            <title><![CDATA[I Tested Dozens of Productivity Tools. This One Changed How I Actually Get Work Done.]]></title>
            <link>https://medium.com/codetodeploy/i-tested-dozens-of-productivity-tools-this-one-changed-how-i-actually-get-work-done-5ea0e6d02ec2?source=rss----c8b549b355f4---4</link>
            <guid isPermaLink="false">https://medium.com/p/5ea0e6d02ec2</guid>
            <category><![CDATA[notebooklm]]></category>
            <category><![CDATA[productivity]]></category>
            <category><![CDATA[ai-productivity]]></category>
            <category><![CDATA[artificial-intelligence]]></category>
            <category><![CDATA[gemini-notebook]]></category>
            <dc:creator><![CDATA[CFir]]></dc:creator>
            <pubDate>Sun, 18 Oct 2026 17:22:23 GMT</pubDate>
            <atom:updated>2026-10-18T17:22:21.938Z</atom:updated>
            <content:encoded><![CDATA[<h4>Most of them made me feel more organized without actually changing anything. This one was different.</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*v9Qd6VK4_7gIGdIwW400ug.png" /></figure><p>Over the past couple of years I’ve cycled through more productivity tools than I’d like to admit — task managers, note-taking apps, elaborate second-brain systems, project trackers, calendar apps promising to fix my scheduling problems. Most of them followed the same arc: genuine enthusiasm for the first week, diminishing use over the following month, and eventual quiet abandonment once the novelty wore off and the actual habit of maintaining the system started competing with the work the system was supposed to support.</p><blockquote><em>💥 </em><strong><em>Master AI &amp; Tech Skills</em></strong><br>💰 One Plan. Multiple Courses. More Savings.<br>🔥 Get Up to 50% OFF | ⏰ Limited-Time Offer<br><a href="http://trk.udemy.com/OYJoKA"><em>👉 </em><strong><em>Enroll Now &amp; Start Learning</em></strong></a></blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ITogvtC6mF2BUF35Qsd9pg.png" /></figure><p>Gemini Notebook is the first one in a long time that didn’t follow that pattern. I want to walk through why, because I think the reason is more specific and more useful than “it’s just a good tool.”</p><p>But before we get into it.</p><p>If you want to get more out of Gemini Notebook (former NotebookLM) than just the basics, if created the NotebookLM Operating System including 120+ premium Gemini Notebook prompts, complete workflows, and AI systems. It’s still named after the tool’s old identity, NotebookLM, but everything in it applies directly to Gemini Notebook.</p><p><strong>👉 </strong><a href="https://cfir.gumroad.com/l/TheNotebookLMOperatingSystem"><strong>Get Your Copy of The NotebookLM Operating System</strong></a></p><h3>Why Most Productivity Tools Fail the Same Way</h3><p>Looking back at everything I abandoned, there’s a common thread I didn’t notice until I’d already dropped most of them. Nearly every tool I tried required me to maintain it — to tag things correctly, file them into the right category, keep a system tidy enough that it stayed useful. The tool itself did very little of the actual work. It was a structure I had to feed and preserve, and the moment I got busy or tired, maintaining the structure was the first thing to slip, which meant the tool stopped being useful right when I needed it most.</p><p>That’s the pattern I think most productivity tooling gets fundamentally backwards. The promise is always “this will make you more organized,” but the actual mechanism is usually “here’s a more elaborate place to put things, which you now have to maintain correctly for it to work.” The maintenance burden is the hidden cost that never shows up in the pitch.</p><h3>What Actually Made This One Different</h3><p>Gemini Notebook doesn’t ask for the same kind of ongoing curation discipline. You upload material — documents, notes, transcripts, whatever’s actually relevant — and instead of needing to tag and file it perfectly to get value later, you just ask direct questions against it whenever you need something. The organizational burden that used to sit entirely on me got replaced by something closer to: dump it in, ask when you need it, and let the tool do the work of finding what’s actually relevant.</p><p>That shift matters more than it sounds like it should. Every previous system I’d tried put the retrieval burden on my own future memory — remembering which tag I used, which folder something lived in, roughly when I’d written it down. This one puts retrieval on the tool instead, and because every answer comes grounded in a citation pointing back to the actual source, I trust the output enough to actually rely on it rather than double-checking everything out of habit built up from tools that occasionally got things wrong with no way to verify.</p><h3>The Specific Moment I Noticed the Difference</h3><p>I can point to a fairly ordinary week where the difference became obvious rather than theoretical. I had three separate client calls in one day, each requiring a different kind of preparation, and under my old approach — scattered notes across a couple of apps, some things written down, plenty of context living only in my memory — prep for that day would normally have eaten an hour or more, digging through old messages and trying to reconstruct where each relationship currently stood.</p><p>Instead, each client already had a notebook I’d been adding to as things happened over the previous months. Prep for all three calls combined took maybe fifteen minutes — a few direct questions per notebook, answers grounded in what was actually said rather than my possibly-faulty recollection of it. That compounding effect, where each notebook gets more valuable specifically because I’d kept adding to it without much conscious effort, is the part no other tool I’d tried ever delivered. Most of them front-loaded effort and delivered diminishing returns. This one did the opposite.</p><h3>Why I Think This One Actually Stuck</h3><p>I think the honest answer is that it removed the specific failure point that killed everything else I’d tried: the requirement to maintain a system perfectly for it to remain useful. Uploading a document takes seconds and requires no decision about where it “belongs” in some elaborate taxonomy I’d have to remember later. Asking a question when I actually need an answer requires no advance planning. The tool does the organizational work I used to have to do manually and inconsistently, and inconsistency was always what killed my previous systems — not any single missed day, but the slow accumulation of small maintenance gaps until the whole system felt too messy to trust.</p><p>I don’t think this is a universal fix for every productivity problem, and I’d be skeptical of anyone claiming a single tool solves organization entirely. But for the specific problem of accumulating and retrieving knowledge about ongoing work — clients, projects, research — it’s the first tool in a genuinely long list that didn’t quietly stop being useful once the initial enthusiasm wore off.</p><h3>What I’d Actually Tell Someone Starting Out</h3><p>If you’ve been through the same cycle I have — genuine enthusiasm for a new system, followed by slow abandonment once maintaining it became its own chore — I’d suggest starting with exactly one notebook around whatever’s currently causing you the most friction, rather than trying to rebuild your entire organizational life around this at once. Let it prove itself on one real problem before expanding, the same way it did for me with that first client notebook, months before I trusted it enough to build the habit out further.</p><p>The tools that actually last aren’t usually the ones with the most features. They’re the ones that ask the least of you to keep working, and this is the first one in a long time that’s actually met that bar for me.</p><p>If you want a structured starting point instead of figuring out the setup by trial and error the way I did, <a href="https://cfir.gumroad.com/">The NotebookLM Operating System</a> covers exactly that: 120+ ready-to-use prompts, 20 frameworks, and 15 complete workflows for research, learning, writing, and business use cases.</p><p>👉 <a href="https://cfir.gumroad.com/l/TheNotebookLMOperatingSystem"><strong>Get The NotebookLM Operating System</strong></a></p><h3>Thank you for being a part of the community</h3><p><em>Before you go:</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*d9QTaaaxboQP_gKSLedW_w.png" /></figure><p>👉 Be sure to <strong>clap</strong> and <strong>follow</strong> the writer ️👏<strong>️️</strong></p><p>👉 Follow us: <a href="https://medium.com/codetodeploy"><strong>Medium</strong></a></p><p>👉 CodeToDeploy Tech Community is live on Discord — <a href="https://discord.gg/ZpwhHq6D"><strong>Join now!</strong></a></p><p><strong>Disclosure:</strong> This post includes affiliate and partnership links.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=5ea0e6d02ec2" width="1" height="1" alt=""><hr><p><a href="https://medium.com/codetodeploy/i-tested-dozens-of-productivity-tools-this-one-changed-how-i-actually-get-work-done-5ea0e6d02ec2">I Tested Dozens of Productivity Tools. This One Changed How I Actually Get Work Done.</a> was originally published in <a href="https://medium.com/codetodeploy">CodeToDeploy</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Securing your LLM harness, your system and your environment. A pluggable security architecture.]]></title>
            <description><![CDATA[<div class="medium-feed-item"><p class="medium-feed-image"><a href="https://medium.com/codetodeploy/securing-your-llm-harness-your-system-and-your-environment-a-pluggable-security-architecture-68d12ab18b90?source=rss----c8b549b355f4---4"><img src="https://cdn-images-1.medium.com/max/1024/1*h_ujOVqaOQHLRg1ybcFZpA.jpeg" width="1024"></a></p><p class="medium-feed-snippet">Treat LLM tool calls like OS syscalls with a Security system.</p><p class="medium-feed-link"><a href="https://medium.com/codetodeploy/securing-your-llm-harness-your-system-and-your-environment-a-pluggable-security-architecture-68d12ab18b90?source=rss----c8b549b355f4---4">Continue reading on CodeToDeploy »</a></p></div>]]></description>
            <link>https://medium.com/codetodeploy/securing-your-llm-harness-your-system-and-your-environment-a-pluggable-security-architecture-68d12ab18b90?source=rss----c8b549b355f4---4</link>
            <guid isPermaLink="false">https://medium.com/p/68d12ab18b90</guid>
            <category><![CDATA[security]]></category>
            <category><![CDATA[python]]></category>
            <category><![CDATA[rbac-access-control]]></category>
            <category><![CDATA[llm]]></category>
            <category><![CDATA[ai]]></category>
            <dc:creator><![CDATA[jon allen]]></dc:creator>
            <pubDate>Sun, 18 Oct 2026 17:21:26 GMT</pubDate>
            <atom:updated>2026-10-18T17:21:25.724Z</atom:updated>
        </item>
        <item>
            <title><![CDATA[10 Foundational AI Agent Papers Every Engineer Should Understand in 2026]]></title>
            <description><![CDATA[<div class="medium-feed-item"><p class="medium-feed-image"><a href="https://medium.com/codetodeploy/10-foundational-ai-agent-papers-every-engineer-should-understand-in-2026-c4fbeb0eeb9c?source=rss----c8b549b355f4---4"><img src="https://cdn-images-1.medium.com/max/1671/1*DzxnQE-aMj7ssEhh36grWA.png" width="1671"></a></p><p class="medium-feed-snippet">From reasoning and tool calling to memory, self-improvement, and multi-agent systems &#x2014; with practical examples you can apply to real&#x2026;</p><p class="medium-feed-link"><a href="https://medium.com/codetodeploy/10-foundational-ai-agent-papers-every-engineer-should-understand-in-2026-c4fbeb0eeb9c?source=rss----c8b549b355f4---4">Continue reading on CodeToDeploy »</a></p></div>]]></description>
            <link>https://medium.com/codetodeploy/10-foundational-ai-agent-papers-every-engineer-should-understand-in-2026-c4fbeb0eeb9c?source=rss----c8b549b355f4---4</link>
            <guid isPermaLink="false">https://medium.com/p/c4fbeb0eeb9c</guid>
            <category><![CDATA[llm]]></category>
            <category><![CDATA[ai-agent]]></category>
            <category><![CDATA[agentic-ai]]></category>
            <category><![CDATA[ai-tools]]></category>
            <category><![CDATA[ai]]></category>
            <dc:creator><![CDATA[Sachin Kasana]]></dc:creator>
            <pubDate>Sun, 18 Oct 2026 17:14:18 GMT</pubDate>
            <atom:updated>2026-10-18T17:14:17.307Z</atom:updated>
        </item>
        <item>
            <title><![CDATA[Building a Ticket Router with OpenAI’s Decisions API]]></title>
            <link>https://medium.com/codetodeploy/building-a-ticket-router-with-openais-decisions-api-cca668b5d543?source=rss----c8b549b355f4---4</link>
            <guid isPermaLink="false">https://medium.com/p/cca668b5d543</guid>
            <category><![CDATA[machine-learning]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[artificial-intelligence]]></category>
            <category><![CDATA[api]]></category>
            <category><![CDATA[openai]]></category>
            <dc:creator><![CDATA[M. Haseeb Hassan]]></dc:creator>
            <pubDate>Sun, 18 Oct 2026 17:12:21 GMT</pubDate>
            <atom:updated>2026-10-18T17:12:20.735Z</atom:updated>
            <content:encoded><![CDATA[<p>A support inbox gets a ticket at 2 a.m. that says the shipment never arrived, and somewhere downstream a router has to decide, in under a second, whether that’s a shipping question, a billing dispute, or something urgent enough to wake someone up. Most teams solve that with a chat model: prompt it, ask for JSON, hope the model doesn’t wrap the answer in a sentence of preamble. OpenAI’s new Decisions API skips that whole negotiation. You send it a question with a fixed set of possible answers, and it gives you back a typed answer, not prose.</p><figure><img alt="Illustrated ticket cards funnel into three labeled sort bins: urgent, department, severity" src="https://cdn-images-1.medium.com/max/1024/1*PoRrPNxa3JqmYx0gbZVjzw.png" /><figcaption><em>Three typed questions, one funnel: predicate, choice, and score sort each ticket before a human ever sees it.</em></figcaption></figure><blockquote><em>💥 </em><strong><em>Master AI &amp; Tech Skills</em></strong><br>💰 One Plan. Multiple Courses. More Savings.<br>🔥 Get Up to 50% OFF | ⏰ Limited-Time Offer<br><a href="http://trk.udemy.com/OYJoKA"><em>👉 </em><strong><em>Enroll Now &amp; Start Learning</em></strong></a></blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ITogvtC6mF2BUF35Qsd9pg.png" /></figure><p><strong>In this article:</strong></p><ul><li>What the Decisions API returns instead of free-text generation</li><li>The three question types: predicate, choice, and score, and when each one fits</li><li>A working ticket-router example that classifies urgency, department, and severity in a single call</li><li>What $0.10 per million input tokens actually means once you’re running this at ticket volume</li><li>What OpenAI hasn’t confirmed yet, and why that matters before you wire this into production</li></ul><h3>What the Decisions API returns instead of prose</h3><p>The Decisions API is a separate endpoint, POST /v1/decisions, built specifically for classification, routing, and scoring rather than open-ended generation [1]. Instead of asking a model to write an answer and parsing it afterward, you send it input (text, images, or both) plus an array of questions, and each question comes back with a structured answer rather than a paragraph [1]. The only model it currently runs on is gpt-6-luna, which OpenAI describes elsewhere as the smallest and cheapest model in its current lineup [2]. That&#39;s a deliberate pairing: a small model doing a narrow job, not a flagship model writing an essay about whether a ticket is urgent.</p><p>This matters for a ticket router specifically because the failure mode of a chat-based classifier usually isn’t “wrong answer.” It’s inconsistent formatting: sometimes a clean JSON object, sometimes a JSON object with a stray markdown fence around it, sometimes an apology followed by the answer you wanted three sentences later. I wrote about the same underlying problem on the Claude side in <a href="https://medium.com/gitconnected/claude-api-structured-outputs-schemas-not-hope-952284782089">Claude API structured outputs: schemas, not hope</a>: a schema doesn’t make a model smarter, it just stops you from parsing its mood. The Decisions API takes that one step further by not giving the model room to wrap the answer in anything at all.</p><figure><img alt="Flow diagram of a ticket routed through predicate, choice, and score questions to a router" src="https://cdn-images-1.medium.com/max/1024/1*1edWHV0PPhb2zr2rIO11UA.png" /><figcaption><em>One request to POST /v1/decisions answers three independent questions in parallel.</em></figcaption></figure><h3>Predicate, choice, and score: the three question types</h3><p>Every question you send has one of three types, and each one returns a different shape of answer [1].</p><p>A predicate question checks whether something is true and returns a probability between 0 and 1, not a flat yes or no [1]. Use it for a single binary gate: is this ticket a safety issue, does this product photo show visible damage, should this message be escalated right now.</p><p>A choice question picks exactly one option from a list you supply, and the response includes the chosen option plus a probabilities array across every option and an overall confidence score [1]. This is the one you reach for when the categories are unordered: billing, technical, shipping, or &quot;other,&quot; with no department more severe than another.</p><p>A score question rates the input against ordered levels, like a severity scale, and returns a probability-weighted average across those levels rather than a single discrete pick [1]. OpenAI&#39;s own documentation example rates an issue across three severity levels and gets back a score of 1.1 from level probabilities of 0.1, 0.7, and 0.2, which tells you the model is fairly confident it&#39;s &quot;medium&quot; severity but hasn&#39;t ruled out &quot;high&quot; [1]. That&#39;s a more honest signal than a model just saying &quot;medium.&quot;</p><figure><img alt="Table comparing predicate, choice, and score question types and their return values" src="https://cdn-images-1.medium.com/max/1024/1*MB6bQaQ9db-JhWUG4VPYHA.png" /><figcaption><em>Choice fits unordered categories; score fits ordered levels like severity.</em></figcaption></figure><p>OpenAI’s guidance is straightforward on when to pick which: use choice for categories that don&#39;t have a natural order, and score for ones that do, like severity or urgency [1]. If what you actually need is a well-formed object rather than an answer to a specific question, the guide points you back toward Structured Outputs or function calling instead [1]. That&#39;s a useful line to draw for anyone tempted to force every classification task through this one endpoint.</p><h3>Building a ticket router in one request</h3><p>A ticket router usually needs to answer three things at once: is this urgent, which department owns it, and how severe is it. Because none of those three answers depends on another, they can go in a single request. OpenAI’s docs are explicit that independent questions can share one call, and only genuinely dependent decisions, where one answer should change what you even ask next, need separate requests [1].</p><p>Here’s the shape of that request, built directly from the documented fields rather than guessed:</p><figure><img alt="Python code posting a ticket to the Decisions API with predicate, choice, and score questions" src="https://cdn-images-1.medium.com/max/1024/1*BUX6uvCzH3LaY3jQOID6yg.png" /><figcaption><em>The three questions share one request because none depends on another’s answer.</em></figcaption></figure><pre>import requests<br><br>response = requests.post(<br>    &quot;https://api.openai.com/v1/decisions&quot;,<br>    headers={&quot;Authorization&quot;: f&quot;Bearer {OPENAI_API_KEY}&quot;},<br>    json={<br>        &quot;model&quot;: &quot;gpt-6-luna&quot;,<br>        &quot;input&quot;: ticket_text,<br>        &quot;questions&quot;: [<br>            {<br>                &quot;name&quot;: &quot;is_urgent&quot;,<br>                &quot;type&quot;: &quot;predicate&quot;,<br>                &quot;instructions&quot;: &quot;Does this ticket describe a safety issue, a security issue, or an outage affecting a paying customer right now?&quot;<br>            },<br>            {<br>                &quot;name&quot;: &quot;department&quot;,<br>                &quot;type&quot;: &quot;choice&quot;,<br>                &quot;instructions&quot;: &quot;Which team should own this ticket?&quot;,<br>                &quot;choices&quot;: [&quot;billing&quot;, &quot;technical&quot;, &quot;shipping&quot;, &quot;other&quot;]<br>            },<br>            {<br>                &quot;name&quot;: &quot;severity&quot;,<br>                &quot;type&quot;: &quot;score&quot;,<br>                &quot;instructions&quot;: &quot;Rate how severe this issue is.&quot;,<br>                &quot;levels&quot;: [&quot;low&quot;, &quot;medium&quot;, &quot;high&quot;]<br>            }<br>        ]<br>    }<br>)<br><br>answers = {a[&quot;name&quot;]: a for a in response.json()[&quot;answers&quot;]}</pre><p>Each answer in the response is keyed by the name you gave its question, so answers[&quot;department&quot;][&quot;choice&quot;] gives you the department string and answers[&quot;department&quot;][&quot;confidence&quot;] tells you how sure the model was [1]. That confidence number is the part most teams skip in a first pass and regret later: a department pick with 0.52 confidence across four options is barely better than a coin flip, and routing it straight to an agent queue without a human glance is how misrouted tickets happen quietly, at scale, for weeks before anyone notices the pattern. I covered the broader version of &quot;the model picked something, but should you trust the pick&quot; in <a href="https://medium.com/gitconnected/mcp-tool-design-why-your-agent-keeps-calling-the-wrong-tool-d57559dfbbe2">MCP tool design: why your agent keeps calling the wrong tool</a>, and the same instinct applies here: a low-confidence choice is a signal to route to a human, not a signal to retry the same question and hope for a cleaner answer.</p><p>One more constraint worth knowing before you reach for this on image-heavy tickets: inline images have to be base64 data URLs. Hosted HTTP or HTTPS image URLs and file_id references aren&#39;t supported on this endpoint [1], which is a step back from what the Responses API allows and worth checking before you assume your existing image-handling code will work unchanged.</p><h3>What it costs, and why that matters at ticket volume</h3><p>OpenAI’s own guide states the rate plainly: gpt-6-luna input on this endpoint costs $0.10 per million tokens, and there are no output, cache-read, or cache-write charges at all, only input [1]. That&#39;s an unusually simple pricing model for an OpenAI endpoint, and it&#39;s corroborated by independent coverage of the public beta launch, which reports the same $0.10-per-million input rate with no output fee [3]. A short support ticket plus a few hundred tokens of instructions is nowhere near a million tokens, so the real cost conversation for most teams isn&#39;t the per-call price, it&#39;s the volume: a help desk running 50,000 tickets a day through three questions each is still, at typical ticket lengths, a fraction of a cent per ticket.</p><p>The more useful comparison isn’t dollars, it’s what that price is buying you instead of a general-purpose chat completion. I built out a similar cost-versus-capability framework for Claude’s model tiers in <a href="https://medium.com/gitconnected/choosing-between-opus-sonnet-and-haiku-a-cost-framework-7252414a3e1c">Choosing Between Opus, Sonnet, and Haiku: A Cost Framework</a>, and the logic transfers directly: the question isn’t “which model is cheapest,” it’s “which model is cheapest for the narrowest version of the task I actually need done.” A ticket router needs a probability and a label, not a model capable of writing a novel, and the pricing here reflects that OpenAI built a separate, narrower product rather than just discounting an existing one.</p><figure><img alt="Stat card showing $0.10 per 1 million input tokens with no output charge" src="https://cdn-images-1.medium.com/max/1024/1*5Q5TfpTJcF5Xh0I-P2C3FA.png" /><figcaption><em>gpt-6-luna on the Decisions endpoint bills only input tokens, per OpenAI’s own pricing guide.</em></figcaption></figure><p>OpenAI also claims the Decisions endpoint runs meaningfully faster than routing the same question through the general-purpose Responses API on the same underlying model, and independent reporting puts that at roughly 150 milliseconds for a decision versus about 1.6 seconds through Responses, though that specific pair of numbers comes from OpenAI via secondary reporting rather than OpenAI’s own published benchmark page, so treat it as a directional claim rather than a guaranteed figure for your own workload [2].</p><h3>The GA gap: what’s still unverified</h3><p>The timeline here is worth getting right, because it moved in two distinct steps. OpenAI first showed the Decisions API at its DevDay event on September 29, 2026, and at that point it was in limited preview with no pricing disclosed [2]. It then opened to all developers in public beta around October 6, 2026, and that’s the point at which the $0.10-per-million pricing actually became public [3]. As of this writing, OpenAI’s own documentation describes general availability as expected “in the coming weeks” without committing to a firm date, so anyone building on this now is building on a beta endpoint, not a GA one [1]. That’s not a reason to avoid it for a prototype, but it is a reason to keep a fallback path in your routing logic rather than hard-coding a dependency on an endpoint that can still change shape.</p><p>A few things genuinely aren’t confirmed yet, and I’d rather say that plainly than guess: how many candidate choice options a single question can hold, whether you can fine-tune or otherwise adapt the underlying judgment to your own labeled data, and how the endpoint behaves under the kind of sustained, bursty load a real support queue produces. If you&#39;re routing anything where a wrong department assignment has real cost, like a ticket that should&#39;ve been flagged as a security issue, the discipline I wrote about in <a href="https://medium.com/gitconnected/what-to-log-before-your-agent-fails-in-production-aa594d6d134d">What to Log Before Your Agent Fails in Production</a> still applies here: log the full answer object, including the confidence and probability fields, not just the final label you acted on, because that&#39;s the only way you&#39;ll be able to tell a genuinely hard ticket from a model that&#39;s quietly getting worse at its one job.</p><h3>Sources</h3><ol><li><a href="https://developers.openai.com/api/docs/guides/decisions">Decisions, OpenAI Developer Platform</a></li><li><a href="https://thenewstack.io/openai-decision-api-luna/">OpenAI’s Decision API Luna, The New Stack</a></li><li><a href="https://letsdatascience.com/news/openai-opens-decisions-api-public-beta-b69a1e40">OpenAI Opens Decisions API Public Beta, Let’s Data Science</a></li></ol><p>If you enjoyed the article and wish to show your support, make sure to:</p><ul><li>👏 Give a round of applause (50 claps) to help get featured</li><li>👥 Follow me on <a href="https://medium.com/@thehaseebhassan">Medium</a> to stay updated with my latest content</li><li>📰 Explore more articles on my <a href="https://medium.com/@thehaseebhassan">Medium Profile</a></li><li>🔔 Connect with me on <a href="http://linkedin.com/in/thehaseebhassan">LinkedIn</a>, <a href="http://twitter.com/thehaseebhassan">Twitter</a>, and <a href="https://instagram.com/the_haseebhassan">Instagram</a></li></ul><h3>Thank you for being a part of the community</h3><p><em>Before you go:</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*d9QTaaaxboQP_gKSLedW_w.png" /></figure><p>👉 Be sure to <strong>clap</strong> and <strong>follow</strong> the writer ️👏<strong>️️</strong></p><p>👉 Follow us: <a href="https://medium.com/codetodeploy"><strong>Medium</strong></a></p><p>👉 CodeToDeploy Tech Community is live on Discord — <a href="https://discord.gg/ZpwhHq6D"><strong>Join now!</strong></a></p><p><strong>Disclosure:</strong> This post includes affiliate and partnership links.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=cca668b5d543" width="1" height="1" alt=""><hr><p><a href="https://medium.com/codetodeploy/building-a-ticket-router-with-openais-decisions-api-cca668b5d543">Building a Ticket Router with OpenAI’s Decisions API</a> was originally published in <a href="https://medium.com/codetodeploy">CodeToDeploy</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[I Thought I Needed Better Prompts. Claude Code Taught Me Otherwise]]></title>
            <description><![CDATA[<div class="medium-feed-item"><p class="medium-feed-image"><a href="https://medium.com/codetodeploy/i-thought-i-needed-better-prompts-claude-code-taught-me-otherwise-ca0583b9a372?source=rss----c8b549b355f4---4"><img src="https://cdn-images-1.medium.com/max/2600/0*_9AnMaLajO4a87vr" width="3882"></a></p><p class="medium-feed-snippet">I spent too much time trying to find the perfect prompt. Then I realized my biggest coding problems had very little to do with how I asked&#x2026;</p><p class="medium-feed-link"><a href="https://medium.com/codetodeploy/i-thought-i-needed-better-prompts-claude-code-taught-me-otherwise-ca0583b9a372?source=rss----c8b549b355f4---4">Continue reading on CodeToDeploy »</a></p></div>]]></description>
            <link>https://medium.com/codetodeploy/i-thought-i-needed-better-prompts-claude-code-taught-me-otherwise-ca0583b9a372?source=rss----c8b549b355f4---4</link>
            <guid isPermaLink="false">https://medium.com/p/ca0583b9a372</guid>
            <category><![CDATA[coding]]></category>
            <category><![CDATA[python]]></category>
            <category><![CDATA[data-science]]></category>
            <category><![CDATA[technology]]></category>
            <category><![CDATA[programming]]></category>
            <dc:creator><![CDATA[Muhummad Zaki]]></dc:creator>
            <pubDate>Sun, 18 Oct 2026 17:11:18 GMT</pubDate>
            <atom:updated>2026-10-18T17:11:17.414Z</atom:updated>
        </item>
        <item>
            <title><![CDATA[ Linux Server Suddenly Rebooted? 10 Commands to Find the Root Cause]]></title>
            <link>https://medium.com/codetodeploy/linux-server-suddenly-rebooted-10-commands-to-find-the-root-cause-c1ae5415a614?source=rss----c8b549b355f4---4</link>
            <guid isPermaLink="false">https://medium.com/p/c1ae5415a614</guid>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[technology]]></category>
            <category><![CDATA[coding]]></category>
            <dc:creator><![CDATA[Saad Khan]]></dc:creator>
            <pubDate>Sun, 18 Oct 2026 17:10:16 GMT</pubDate>
            <atom:updated>2026-10-18T17:10:14.859Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*58icZlYpAv1c3NP185hRDw@2x.jpeg" /></figure><p>Your Linux server rebooted unexpectedly? Learn how to investigate previous-boot logs, kernel errors, OOM kills, crash dumps, and system events using practical commands on RHEL and Linux.</p><blockquote><em>💥 </em><strong><em>Master AI &amp; Tech Skills</em></strong><br>💰 One Plan. Multiple Courses. More Savings.<br>🔥 Get Up to 50% OFF | ⏰ Limited-Time Offer<br><a href="http://trk.udemy.com/OYJoKA"><em>👉 </em><strong><em>Enroll Now &amp; Start Learning</em></strong></a></blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ITogvtC6mF2BUF35Qsd9pg.png" /></figure><p>It’s 9:15 AM.</p><p>You log in to your Linux server and notice something unusual.</p><p>The application was unavailable earlier. Users reported a brief outage, but nobody on your team remembers rebooting the server.</p><p>You run:</p><p>uptime</p><p>And discover that the server has been running for only 12 minutes.</p><p>The server rebooted. But why?</p><p>Was it a kernel panic? Did Linux run out of memory? Did someone reboot it manually? Was there a power failure or an issue with the underlying cloud infrastructure?</p><p>As a Linux administrator, you shouldn’t guess.</p><p>You need evidence.</p><p>In this guide, we’ll investigate an unexpected Linux reboot using 10 practical commands, with a focus on RHEL 8 and RHEL 9.</p><p>We’ll also learn what each command can tell us, what it cannot prove, and how to investigate when the logs don’t reveal an obvious answer.</p><p>⸻</p><ol><li>Check the Reboot History</li></ol><p>The first step is to establish when the server rebooted.</p><p>Run:</p><p>last -x | head -20</p><p>This displays recent login and system records, including reboot and shutdown entries when available.</p><p>Example output:</p><p>reboot. system boot. 5.14.0-… Sat Oct 17 09:03</p><p>runlevel (to lvl 5) 5.14.0-…</p><p>shutdown system down. Sat Oct 17 08:58</p><p>reboot. system boot. 5.14.0-… Fri Oct 16 18:20</p><p>Example output only; actual records depend on the system.</p><p>Pay attention to:</p><ul><li>The most recent reboot time</li><li>* Whether a shutdown entry appears before the reboot</li><li>* Whether multiple reboots occurred close together</li><li>* Whether the timestamps align with the reported outage</li></ul><p>You can also run:</p><p>who -b</p><p>This reports the time of the last system boot.</p><p>What does this prove?</p><p>It helps establish the timeline.</p><p>However, last reads accounting records, and the presence or absence of a shutdown entry is not definitive proof of a graceful shutdown or a crash.</p><p>Important: Reboot history tells you when a reboot was recorded, not necessarily why it happened.</p><p>⸻</p><p>2. List Previous System Boots</p><p>On RHEL and other systemd-based Linux distributions, journalctl is one of your most useful troubleshooting tools.</p><p>Start with:</p><p>journalctl – list-boots</p><p>Example:</p><p>IDX. BOOT ID. FIRST ENTRY. LAST ENTRY</p><p>-2. abc123… Thu Oct 15 08:00:00. Thu Oct 15 18:10:00</p><p>-1. def456… Fri Oct 16 09:00:00. Fri Oct 16 18:20:00</p><p>0. ghi789… Sat Oct 17 09:03:00. Sat Oct 17 09:15:00</p><p>The boot indexes mean:</p><ul><li>0 – the current boot</li><li>* -1 – the previous boot</li><li>* -2 – the boot before that</li></ul><p>This is particularly useful when a server has restarted multiple times.</p><p>You can compare boot IDs and timestamps to identify which boot corresponds to the incident.</p><p>A common problem</p><p>You run:</p><p>journalctl – list-boots</p><p>But only the current boot appears.</p><p>Don’t assume the older logs never existed. The journal may not have been configured for persistent storage, or older entries may have been removed by retention or storage limits.</p><p>We’ll discuss that later.</p><p>⸻</p><p>3. Inspect the Previous Boot’s Logs</p><p>Now that you know which boot to investigate, examine its logs.</p><p>Run:</p><p>journalctl -b -1</p><p>This displays the journal entries from the previous boot, if they are available.</p><p>For a more targeted investigation:</p><p>journalctl -b -1 -n 200</p><p>To focus on a time window, use:</p><p>journalctl -b -1 \</p><p>. – since “2026–10–17 08:30:00&quot; \</p><p>. – until “2026–10–17 09:05:00&quot;</p><p>Replace the timestamps with the actual incident window.</p><p>Look for:</p><ul><li>Kernel warnings</li><li>* Failed services</li><li>* Storage or filesystem errors</li><li>* Out-of-memory messages</li><li>* Watchdog events</li><li>* Unexpected shutdown-related messages</li><li>* The last available messages before logging stopped</li></ul><p>Here’s the important part</p><p>Suppose the journal stops at 08:58, and the next boot begins at 09:03.</p><p>That gap is worth investigating, but it does not automatically prove a crash.</p><p>A sudden loss of power, a hypervisor reset, a hardware hang, or missing persistent logs can produce an incomplete record.</p><p>The final log message is a clue, not automatically the root cause.</p><p>⸻</p><p>4. Find Errors From the Previous Boot</p><p>Instead of reading thousands of log lines, filter for error-priority messages.</p><p>Run:</p><p>journalctl -b -1 -p err</p><p>To include warnings as well:</p><p>journalctl -b -1 -p warning</p><p>You can also inspect critical messages:</p><p>journalctl -b -1 -p crit</p><p>Example:</p><p>Oct 17 08:52:14 server kernel: …</p><p>Oct 17 08:54:21 server systemd[1]: …</p><p>Oct 17 08:57:42 server kernel: …</p><p>These are illustrative entries. Your actual output depends on the incident.</p><p>Don’t immediately assume the first error caused the reboot.</p><p>An error may have occurred hours before the incident without being related to it. Correlate the timestamp, affected component, and surrounding messages.</p><p>For example, if you find filesystem errors just before the system becomes unresponsive, investigate the storage path and kernel logs next.</p><p>⸻</p><p>5. Investigate Kernel Messages</p><p>If you suspect a kernel panic, hardware issue, driver problem, or watchdog event, inspect the previous boot’s kernel messages.</p><p>Run:</p><p>journalctl -k -b -1</p><p>To search for relevant terms:</p><p>journalctl -k -b -1 |</p><p>grep -Ei ‘panic|oops|watchdog|hung task|I/O error|hardware error’</p><p>This can reveal messages associated with:</p><ul><li>Kernel panics or oopses</li><li>* Hung tasks</li><li>* Watchdog events</li><li>* Storage I/O errors</li><li>* Driver problems</li><li>* Hardware-related errors</li></ul><p>For example, you might discover repeated storage I/O errors shortly before the server stopped responding.</p><p>That points toward further investigation of the storage device, virtual disk, storage backend, or driver.</p><p>What if the previous boot’s kernel logs are missing?</p><p>Try:</p><p>journalctl -k -b -1</p><p>If the previous boot is unavailable, there may be no retained journal data to inspect.</p><p>The current command:</p><p>dmesg -T</p><p>shows messages from the currently running kernel’s ring buffer. It is not a substitute for the previous boot’s logs.</p><p>For a kernel crash, a configured crash dump may provide more evidence.</p><p>⸻</p><p>6. Check Whether Linux Killed a Process Because of Memory Pressure</p><p>An out-of-memory event can terminate an application without necessarily rebooting the entire server.</p><p>That’s why you should investigate memory-related events rather than assuming every unexpected reboot was caused by an OOM kill.</p><p>Search the previous boot’s journal:</p><p>journalctl -k -b -1 |</p><p>grep -Ei ‘out of memory|oom-kill|killed process’</p><p>You might find a message similar to:</p><p>Out of memory: Killed process 2458 (java) …</p><p>This indicates that the kernel killed a process due to memory pressure.</p><p>It does not by itself prove that the OOM event caused the server to reboot.</p><p>Investigate the surrounding logs and determine whether the event affected an application, a critical system service, or the entire machine.</p><p>If the system is currently running, inspect memory usage:</p><p>free -h</p><p>Check the current processes:</p><p>ps aux – sort=-%mem | head</p><p>These commands show the current state, not necessarily the memory state during the previous boot.</p><p>For historical memory evidence, you may need monitoring data, application metrics, or previously collected system statistics.</p><p>⸻</p><p>7. Look for Evidence of a Kernel Crash</p><p>If the journal suggests a kernel panic or severe system failure, check whether crash dumps were collected.</p><p>On RHEL, the kdump mechanism can capture kernel memory in a vmcore file for post-incident analysis.</p><p>Check the current status:</p><p>kdumpctl status</p><p>Inspect the configured crash-dump destination:</p><p>cat /etc/kdump.conf</p><p>Then inspect the default crash directory, if configured:</p><p>ls -lah /var/crash/</p><p>You may find a directory containing files such as:</p><p>vmcore</p><p>vmcore-dmesg.txt</p><p>kexec-dmesg.log</p><p>The exact files and directory structure depend on the system and its kdump configuration.</p><p>The vmcore file can contain valuable information about the kernel’s state at the time of a crash. It may require the matching kernel and debugging information for analysis.</p><p>Red Hat documents kdump as a mechanism for capturing kernel memory after a crash. See the RHEL 9 kdump documentation.</p><p>Important: A missing vmcore does not prove that a kernel crash did not happen. Kdump may not have been configured, may have failed to capture the dump, or may use a different destination.</p><p>Never deliberately crash a production server to test kdump.</p><p>⸻</p><p>8. Check Failed Services After the Reboot</p><p>Once the server has returned, inspect services that are currently failing.</p><p>Run:</p><p>systemctl – failed</p><p>Example:</p><p>UNIT. LOAD. ACTIVE. SUB. DESCRIPTION</p><p>myapp.service. loaded failed. failed. Application Service</p><p>Then investigate an affected service:</p><p>systemctl status myapp.service</p><p>Review its current logs:</p><p>journalctl -u myapp.service -b</p><p>A service might have failed because of the reboot, or its failure might be related to the original incident.</p><p>For example, a database service could fail to start because its filesystem is unavailable or because a required dependency has not started.</p><p>Don’t assume a service failure caused the reboot just because it appears after the reboot. Establish the sequence of events first.</p><p>⸻</p><p>9. Verify the Current Boot and System Timeline</p><p>Use:</p><p>uptime</p><p>And:</p><p>who -b</p><p>These help confirm the current boot time.</p><p>Now compare that information with:</p><p>last -x | head -20</p><p>and:</p><p>journalctl – list-boots</p><p>The goal is to build a timeline:</p><ol><li>When was the server last known to be healthy?</li><li>2. When did the outage begin?</li><li>3. When did the previous boot’s logs stop?</li><li>4. When did the current boot begin?</li><li>5. Which services failed during startup?</li><li>6. What evidence exists immediately before the incident?</li></ol><p>If the machine restarted more than once, investigate each boot separately using the appropriate boot index.</p><p>This is especially important for systems that repeatedly crash during startup.</p><p>⸻</p><p>10. Check the Infrastructure and External Events</p><p>Sometimes the operating system cannot tell you why the server restarted.</p><p>For a virtual machine or cloud instance, the cause may be outside the guest operating system.</p><p>Check the relevant infrastructure records for:</p><ul><li>Hypervisor or host maintenance</li><li>* Cloud instance stop/start or reboot events</li><li>* Provider-reported system status events</li><li>* Virtual machine reset events</li><li>* Storage or network infrastructure incidents</li><li>* Monitoring alerts around the same timestamp</li></ul><p>For AWS EC2, for example, review the instance’s status checks, relevant scheduled events, and available CloudTrail events around the incident.</p><p>For Azure or VMware, use the corresponding platform’s activity and event logs.</p><p>A guest operating system may show a new boot without retaining enough information to explain why it happened.</p><p>If the operating system logs end abruptly and there is no crash dump, external infrastructure evidence may be the best remaining source.</p><p>⸻</p><p>A Practical Incident Investigation</p><p>Let’s put the commands together.</p><p>Imagine that monitoring reports an outage at 09:00.</p><p>You log in at 09:15 and run:</p><p>uptime</p><p>The system has been running for 12 minutes.</p><p>First, establish the reboot history:</p><p>last -x | head -20</p><p>Next, identify the previous boot:</p><p>journalctl – list-boots</p><p>Inspect the previous boot:</p><p>journalctl -b -1 -n 200</p><p>Filter kernel errors:</p><p>journalctl -k -b -1 |</p><p>grep -Ei ‘panic|oops|watchdog|hung task|I/O error|hardware error’</p><p>Check for memory-related events:</p><p>journalctl -k -b -1 |</p><p>grep -Ei ‘out of memory|oom-kill|killed process’</p><p>Finally, inspect crash-dump evidence:</p><p>kdumpctl status</p><p>ls -lah /var/crash/</p><p>Suppose the previous boot’s logs stop abruptly, no clear panic or OOM evidence is available, and there is no crash dump.</p><p>The correct conclusion is not “the server definitely crashed because of a kernel panic.”</p><p>The correct conclusion is:</p><p>The server rebooted unexpectedly, but the available guest operating system logs do not establish the root cause. Further investigation of persistent logs and infrastructure events is required.</p><p>That is how you avoid reporting assumptions as facts in a production incident.</p><p>⸻</p><p>Bonus: Preserve Logs for the Next Incident</p><p>One of the most frustrating situations is discovering that the logs you need disappeared during the reboot.</p><p>On systemd-based systems, check the journal configuration:</p><p>grep -E ‘^[[:space:]]*Storage=’ /etc/systemd/journald.conf</p><p>If Storage= is commented out or absent, the effective behavior depends on the system’s journal configuration and whether /var/log/journal exists.</p><p>For persistent journal storage, an administrator can configure Storage=persistent in /etc/systemd/journald.conf, create the journal directory with the correct ownership and permissions, and ensure sufficient disk space and suitable retention limits.</p><p>After changing the configuration, follow the system’s journal-management procedure and verify that logs from a subsequent boot are retained.</p><p>Check:</p><p>journalctl – list-boots</p><p>Do not assume persistence is working until you have verified it.</p><p>For more details, see Red Hat’s guidance on distinguishing a crash from a graceful reboot.</p><p>Also consider ensuring that:</p><ul><li>Kdump is appropriately configured and operational.</li><li>* Monitoring captures memory, CPU, disk, and system events.</li><li>* Logs are forwarded to a remote logging system where appropriate.</li><li>* Cloud infrastructure events are retained.</li><li>* Alert timestamps are synchronized across systems.</li></ul><p>Good preparation makes the next investigation much easier.</p><p>⸻</p><p>Quick Reference: 10 Commands for Unexpected Linux Reboots</p><p>Purpose	Command</p><p>Reboot and shutdown records	`last -x</p><p>Last boot time	who -b</p><p>List recorded boots	journalctl – list-boots</p><p>Read previous-boot logs	journalctl -b -1</p><p>Find previous-boot errors	journalctl -b -1 -p err</p><p>Inspect previous-boot kernel logs	journalctl -k -b -1</p><p>Search for OOM events	journalctl -k -b -1 | grep -Ei ‘out of memory|oom-kill|killed process’</p><p>Check failed services	systemctl – failed</p><p>Check current boot time	uptime</p><p>Inspect kdump and crash files	kdumpctl status and ls -lah /var/crash/</p><p>Remember that these commands have different purposes. Some establish the timeline, some reveal symptoms, and others help determine whether a crash dump exists. None can guarantee a root cause on its own.</p><p>⸻</p><p>Final Thoughts</p><p>An unexpected Linux reboot can be caused by many things: a kernel panic, a manual or automated reboot, memory pressure, hardware problems, power loss, a hypervisor event, or another infrastructure issue.</p><p>The most important skill is knowing how to investigate the evidence.</p><p>Start with reboot history. Examine the previous boot. Correlate kernel and system logs. Look for OOM events and crash dumps. Check infrastructure records when the guest operating system cannot explain the event.</p><p>And if the evidence is incomplete, say so.</p><p>A good Linux administrator doesn’t just restore service. They establish what happened, identify what remains unknown, and improve monitoring so the next incident is easier to diagnose.</p><p>If this guide helped you, follow CodeToDeploy for more practical Linux, RHEL, DevOps, and production troubleshooting tutorials.</p><p>Have you ever investigated an unexpected Linux reboot? Share the command or log entry that helped you find the cause.</p><h3>Thank you for being a part of the community</h3><p><em>Before you go:</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*d9QTaaaxboQP_gKSLedW_w.png" /></figure><p>👉 Be sure to <strong>clap</strong> and <strong>follow</strong> the writer ️👏<strong>️️</strong></p><p>👉 Follow us: <a href="https://medium.com/codetodeploy"><strong>Medium</strong></a></p><p>👉 CodeToDeploy Tech Community is live on Discord — <a href="https://discord.gg/ZpwhHq6D"><strong>Join now!</strong></a></p><p><strong>Disclosure:</strong> This post includes affiliate and partnership links.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c1ae5415a614" width="1" height="1" alt=""><hr><p><a href="https://medium.com/codetodeploy/linux-server-suddenly-rebooted-10-commands-to-find-the-root-cause-c1ae5415a614">💥 Linux Server Suddenly Rebooted? 10 Commands to Find the Root Cause</a> was originally published in <a href="https://medium.com/codetodeploy">CodeToDeploy</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>