<?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: Kat Padilla</title>
    <description>The latest articles on DEV Community by Kat Padilla (@katpadi).</description>
    <link>https://dev.to/katpadi</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%2F2012%2FSSZRbdPF.jpg</url>
      <title>DEV Community: Kat Padilla</title>
      <link>https://dev.to/katpadi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/katpadi"/>
    <language>en</language>
    <item>
      <title>My Notes on LLMs</title>
      <dc:creator>Kat Padilla</dc:creator>
      <pubDate>Mon, 22 Jun 2026 13:35:13 +0000</pubDate>
      <link>https://dev.to/katpadi/my-notes-on-llms-589g</link>
      <guid>https://dev.to/katpadi/my-notes-on-llms-589g</guid>
      <description>&lt;p&gt;These notes are my attempt to capture the concepts, observations and references that have helped me make sense of LLMs.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is an LLM
&lt;/h2&gt;

&lt;p&gt;A Large Language Model is a machine learning model trained to predict the next token in a sequence.&lt;/p&gt;

&lt;p&gt;The first thing I had to unlearn: &lt;strong&gt;&lt;u&gt;it's not a search engine&lt;/u&gt;&lt;/strong&gt;. It doesn't look anything up by default. It generates responses based on patterns from training data. That distinction sounds small but it changes how you think about everything else.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key concepts
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Token&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The unit everything is measured in. Roughly 3-4 characters in English text, which loosely maps to about 3/4 of a word. It varies by language and model though. Every message, every reply, every system instruction are all tokens. Most models have a hard cap on how many they can handle at once.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Parameters&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The weights a model learned during training. Bigger models tend to perform better but it's not a clean relationship. Architecture, training data quality and what happened after training all matter too. Parameter count alone stopped being a reliable proxy for capability a while back.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Training vs inference&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Training&lt;/strong&gt; is the model learning from data. It happens once and is genuinely expensive. &lt;strong&gt;Inference&lt;/strong&gt; is me talking to it in real time. I only ever interact during inference. The model's weights don't change mid-conversation. Whatever I tell it lives in the current context window, not in the model itself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Knowledge cutoff&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Training stopped at some date. Anything after that, the model doesn't know unless it has a search tool attached.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hallucination&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When the model generates confident-sounding but false information. It's pattern-matching without a fact-checker. More likely with obscure topics, long conversations or vague prompts. The rule I follow: &lt;u&gt;verify anything that actually matters&lt;/u&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;System prompt&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Hidden instructions loaded before my first message. Sets the model's persona, rules and constraints. I never see it in most interfaces.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Temperature&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Controls how predictable vs adventurous the model's word choices are.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Low (0-0.3):&lt;/strong&gt; consistent, predictable. Good for code and factual answers.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;High (0.7-1.0):&lt;/strong&gt; varied, creative. Good for brainstorming and writing.&lt;/p&gt;

&lt;p&gt;If AI-generated code keeps being weird, temperature is probably too high. If brainstorming outputs all sound identical, too low. Most interfaces default around 0.7. In higher-level interfaces like ChatGPT or Claude.ai, you can't set it directly so prompt phrasing does the steering instead.&lt;/p&gt;

&lt;h2&gt;
  
  
  Turns
&lt;/h2&gt;

&lt;p&gt;A turn is one exchange: I send a message, the model replies. That's it.&lt;/p&gt;

&lt;p&gt;The model doesn't pick up where it left off. Every turn, it re-reads the entire conversation from the beginning: the system prompt, every message I've sent, every reply it's given, any files I've attached. All of it, every single time.&lt;/p&gt;

&lt;p&gt;There's no memory carried over between turns. No state. The conversation history only exists because it gets passed back in as part of the input. If it's not in the context window, it's gone.&lt;/p&gt;

&lt;p&gt;This is also why the model can feel inconsistent mid-conversation. It's not drifting. It's reading more and more tokens each turn and, past a certain point, the earlier parts of the conversation start getting less attention. That re-read behavior is exactly what makes the context window worth understanding.&lt;/p&gt;

&lt;h2&gt;
  
  
  The context window
&lt;/h2&gt;

&lt;p&gt;Everything the model can "see" at once, measured in tokens. Not memory. More like a working scratchpad. Everything the model needs to know about the current task has to fit inside it.&lt;/p&gt;

&lt;h3&gt;
  
  
  The smart zone and the dumb zone
&lt;/h3&gt;

&lt;p&gt;Despite huge advertised context windows, the model doesn't process all tokens equally. This framing comes from &lt;a href="https://www.youtube.com/watch?v=rmvDxxNubIg&amp;amp;ref=blog.katpadi.ph" rel="noopener noreferrer"&gt;Dex Horthy at AI Engineer World's Fair&lt;/a&gt; and it's the most useful mental model I've found for it.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;&lt;em&gt;smart zone&lt;/em&gt;&lt;/strong&gt; is the earlier portion of the context window. Full attention, good reasoning, follows instructions well.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;&lt;em&gt;dumb zone&lt;/em&gt;&lt;/strong&gt; kicks in as the context fills up. Tokens are still technically there, nothing gets deleted, but coherence starts degrading. The model forgets things, gets repetitive, gets vague and starts agreeing with everything.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa74iyxsl9nzad6b5fhjh.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa74iyxsl9nzad6b5fhjh.png" width="799" height="375"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Degradation tends to kick in well before the model hits its actual context limit. The exact threshold varies by model.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The U-curve&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;LLMs pay the most attention to the beginning and end of context. The middle gets ignored. So as a conversation grows, the early stuff, the instructions I set at the start, those drift into exactly the part the model stops caring about. &lt;a href="https://arxiv.org/abs/2307.03172?ref=blog.katpadi.ph" rel="noopener noreferrer"&gt;Stanford researchers&lt;/a&gt; found real performance drops when relevant information sat in the middle of long contexts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Context rot&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The gradual degradation of LLM performance as context grows. &lt;a href="https://trychroma.com/interview-with-a-context-window?ref=blog.katpadi.ph" rel="noopener noreferrer"&gt;Chroma&lt;/a&gt; ran a study across 18 frontier models and found performance decreasing with longer inputs across all tested models, not just some of them.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 When the AI starts saying "you're absolutely right" to everything or forgets what I told it earlier, that's the dumb zone. The fix is starting fresh.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Warning signs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Repeating suggestions it already made&lt;/li&gt;
&lt;li&gt;"You're absolutely right" then ignores what I said&lt;/li&gt;
&lt;li&gt;Forgets rules or constraints from earlier&lt;/li&gt;
&lt;li&gt;Answers get generic and vague&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What eats context fast:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Long conversations&lt;/li&gt;
&lt;li&gt;Pasted files or big code blocks&lt;/li&gt;
&lt;li&gt;Tool integrations (can eat a significant chunk before I type anything)&lt;/li&gt;
&lt;li&gt;The model's own long replies, those go back in too&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Context engineering
&lt;/h2&gt;

&lt;p&gt;Managing what's in the context window deliberately so the model stays in the smart zone. A bit different from prompt engineering.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prompt engineering:&lt;/strong&gt; writing a better single prompt.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Context engineering:&lt;/strong&gt; designing what information reaches the model at all, instructions, retrieved documents, tool outputs, conversation history.&lt;/p&gt;

&lt;p&gt;What I do in practice to stay in the smart zone:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Keep prompts specific. (Vague in, vague out!)&lt;/li&gt;
&lt;li&gt;Start fresh often. New topic means new conversation.&lt;/li&gt;
&lt;li&gt;Front-load the important stuff. Given the U-curve, critical instructions buried mid-conversation get less attention.&lt;/li&gt;
&lt;li&gt;When context gets full, prefer a manual handoff over letting the model auto-summarize. A model that's already degraded writing its own summary is not ideal. I use &lt;a href="https://github.com/mattpocock/skills/blob/main/skills/productivity/handoff/SKILL.md?ref=blog.katpadi.ph" rel="noopener noreferrer"&gt;Matt Pocock's /handoff skill&lt;/a&gt; for this.&lt;/li&gt;
&lt;li&gt;Don't trust large context windows blindly. 1M tokens doesn't mean 1M tokens of reliable reasoning.&lt;/li&gt;
&lt;li&gt;Verify anything that matters. Hallucination is real.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;💡On the auto-summarize thing: by the time the context needs summarizing, the model is already in the dumb zone. A degraded model writing its own summary is not a reliable summary!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What I'm still figuring out
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;RAG (Retrieval-Augmented Generation)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Instead of stuffing everything into the context window, the system retrieves only the relevant pieces when needed, pulling from a database, a document store or a knowledge base. The model never sees the full corpus, just what's relevant to the current query.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Embeddings&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Numerical representations of text that capture meaning. Similar ideas end up close together in vector space, which makes semantic search possible.&lt;/p&gt;

&lt;p&gt;Embeddings are the foundation of RAG, vector databases and many AI memory systems.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Training&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I understand the basic idea: expose the model to enormous amounts of text and for each token it predicts, adjust the weights slightly based on whether it was right. Repeat billions of times. But I don't have a clear picture of what that actually looks like at scale yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://arxiv.org/abs/2307.03172?ref=blog.katpadi.ph" rel="noopener noreferrer"&gt;Lost in the Middle: How Language Models Use Long Contexts — Liu et al., Stanford&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://trychroma.com/interview-with-a-context-window?ref=blog.katpadi.ph" rel="noopener noreferrer"&gt;Chroma: Context Rot Research&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=rmvDxxNubIg&amp;amp;ref=blog.katpadi.ph" rel="noopener noreferrer"&gt;Dex Horthy: Smart Zone / Dumb Zone (AI Engineer World's Fair)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/diggidydale/escaping-the-dumbzone-part-1-why-your-ai-gets-stupider-the-more-you-talk-to-it-4d8k?ref=blog.katpadi.ph"&gt;Lost in the Middle: DEV Community explainer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://garrit.xyz/posts/2026-05-06-dont-trust-large-context-windows?ref=blog.katpadi.ph" rel="noopener noreferrer"&gt;Don't Trust Large Context Windows — Garrit's Notes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>contextengineering</category>
    </item>
    <item>
      <title>It's Markdown's World And We're All Just Living In It</title>
      <dc:creator>Kat Padilla</dc:creator>
      <pubDate>Sat, 06 Jun 2026 07:50:08 +0000</pubDate>
      <link>https://dev.to/katpadi/its-markdowns-world-and-were-all-just-living-in-it-1ngk</link>
      <guid>https://dev.to/katpadi/its-markdowns-world-and-were-all-just-living-in-it-1ngk</guid>
      <description>&lt;p&gt;Funny how I randomly thought: how the heck did &lt;code&gt;.md&lt;/code&gt; files end up basically running the show now? Not just in repos as READMEs. They're literally load-bearing walls in the AI ecosystem and I would've laughed if you told me this a few years back.&lt;/p&gt;

&lt;p&gt;It's a weird arc for a plain text file.&lt;/p&gt;

&lt;h2&gt;
  
  
  The README Era
&lt;/h2&gt;

&lt;p&gt;For most of my career, Markdown meant one thing: README files. You wrote one when you pushed a repo. It explained what the project was, how to run it, maybe a quick example. Nobody was precious about it. It was the file you wrote last, usually when you were already done with your project and slightly exhausted.&lt;/p&gt;

&lt;p&gt;GitHub made it the default in 2008 and that was pretty much that. It lived in repos. It rendered nicely. That's it.&lt;/p&gt;

&lt;p&gt;Nobody sat down and thought: &lt;em&gt;this is going to matter.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;And yet here I am, writing this very post in Markdown as this blog runs on Ghost, and Ghost is Markdown under the hood. Even my note-taking app is Obsidian, which stores every single note as a &lt;code&gt;.md&lt;/code&gt; file. I've been living in Markdown this whole time without really registering it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Quiet Takeover
&lt;/h2&gt;

&lt;p&gt;That thought made me search. And the history is almost too on-the-nose.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://daringfireball.net/projects/markdown/?ref=blog.katpadi.ph" rel="noopener noreferrer"&gt;John Gruber&lt;/a&gt; made it in 2004 because he just didn't want to write HTML by hand. The entire origin story is "this was annoying, let me fix it for myself." Aaron Swartz helped. The first converter was a Perl script.&lt;/p&gt;

&lt;p&gt;That's it. That's the founding mythology of what is now, without exaggeration, critical infrastructure.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://stackoverflow.blog/2008/06/25/three-markdown-gotcha/?ref=blog.katpadi.ph" rel="noopener noreferrer"&gt;Stack Overflow shipped with Markdown support&lt;/a&gt; in 2008. &lt;a href="https://github.blog/engineering/user-experience/a-formal-spec-for-github-markdown/?ref=blog.katpadi.ph" rel="noopener noreferrer"&gt;GitHub made it the face of every open source project&lt;/a&gt;. Static site generators ran on it. Note-taking apps adopted it. And then slowly, quietly, it became the format developers just used, not because someone mandated it, but because plain text that renders well is genuinely hard to beat.&lt;/p&gt;

&lt;p&gt;It won because it was portable. Humans can read it even without rendering. Machines can parse it easily. Copy-pasting between systems just works. It's not perfect. Not elegant. Just compatible with almost everything.&lt;/p&gt;

&lt;p&gt;And then AI showed up.&lt;/p&gt;

&lt;h2&gt;
  
  
  Plot Twist
&lt;/h2&gt;

&lt;p&gt;AI models output Markdown by default now. Every response, every structured answer, every tool output. Headers, bullet points, bold text, code blocks. All of it formatted in a syntax that one blogger invented because he hated angle brackets.&lt;/p&gt;

&lt;p&gt;Agents read it. Agents write it. Headings become context boundaries. Bullet points become instructions. Code fences become executable blocks. Systems are being built where &lt;code&gt;.md&lt;/code&gt; files are the interface between humans and AI, the thing you edit to change how an agent thinks, what it knows, what it does.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SKILL.md. AGENT.md. README.md as configuration.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It's not a document format anymore. It's an instruction layer.&lt;/p&gt;

&lt;p&gt;The format is simple enough for humans but structured enough for machines. That balance is surprisingly rare. And that's exactly why it stuck.&lt;/p&gt;

&lt;h2&gt;
  
  
  Kind of Wild
&lt;/h2&gt;

&lt;p&gt;Gruber didn't design it for agents. He designed it to get out of his own way while writing. And now that's exactly why it works, because it carries meaning without ceremony. No tags. No schemas. No overhead.&lt;/p&gt;

&lt;p&gt;The trillion-dollar AI industry is running on a &lt;a href="https://daringfireball.net/2004/03/introducing_markdown?ref=blog.katpadi.ph" rel="noopener noreferrer"&gt;plain text format someone made for their blog in 2004&lt;/a&gt;. Not because it was engineered for this. Because it was simple enough to survive everything.&lt;/p&gt;

&lt;p&gt;I don't know what that says exactly. But I find it kind of wild.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>markdown</category>
      <category>reflections</category>
      <category>thoughts</category>
    </item>
    <item>
      <title>Brain Dump: AgentCore Gateway</title>
      <dc:creator>Kat Padilla</dc:creator>
      <pubDate>Fri, 05 Jun 2026 12:30:56 +0000</pubDate>
      <link>https://dev.to/katpadi/brain-dump-agentcore-gateway-4c9j</link>
      <guid>https://dev.to/katpadi/brain-dump-agentcore-gateway-4c9j</guid>
      <description>&lt;p&gt;As you build AI agents, they need to call tools: APIs, databases, services. Traditionally you'd write an MCP server for each one. Server scaffolding, tool descriptions, error handling, auth, observability, repeated across every team, every API.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;TIL: You don't always need to write an MCP server&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;If you already have REST APIs with OpenAPI specs, &lt;a href="https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/gateway.html?ref=blog.katpadi.ph" rel="noopener noreferrer"&gt;AgentCore Gateway&lt;/a&gt; can wrap them and expose them as MCP-compatible tools automatically. Just point it at your spec and your endpoints become tools agents can call.&lt;/p&gt;

&lt;p&gt;It also handles inbound auth (who can call the gateway) and outbound auth (how the gateway calls your backend) which are all managed by AWS.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Targets&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;AgentCore Gateway supports multiple &lt;a href="https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/gateway-core-concepts.html?ref=blog.katpadi.ph#gateway-core-concepts-target-types" rel="noopener noreferrer"&gt;target types&lt;/a&gt;. You can wire in AWS Lambda functions, native MCP servers and prebuilt connectors (Slack, Jira, etc. with managed OAuth). One gateway can manage multiple targets, so you end up with a single MCP endpoint that fronts many different backends.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Tool descriptions quality = agent quality&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The documentation in your OpenAPI spec becomes what the agent reads to decide which tool to call and how. Vague or incomplete descriptions directly hurt agent behavior. It may pick the wrong tool or misuse parameters. So apparently, good descriptions aren't just nice to have anymore, they're part of making the agent work correctly.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Size matters in response payloads&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;If your REST endpoints return large, noisy payloads, that gets passed straight to the agent. This is a real concern. Bloated responses eat context window and can confuse the agent. Something to think about before wrapping an API as-is.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Request and response interceptors&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;AgentCore Gateway supports interceptors on both sides of a call.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/gateway-interceptors-types.html?ref=blog.katpadi.ph#gateway-interceptors-types-request" rel="noopener noreferrer"&gt;Request interceptors&lt;/a&gt; run before the call reaches your backend. Useful for injecting auth, adding headers or modifying the request payload on the way in.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/gateway-interceptors-types.html?ref=blog.katpadi.ph#gateway-interceptors-types-response" rel="noopener noreferrer"&gt;Response interceptors&lt;/a&gt; run before the result goes back to the agent. The main use I have in mind is trimming down fat responses so they don't bloat the agent's context. That said, I'm not sure yet if response interceptors are actually the right tool for payload trimming or if it even works well in practice. &lt;em&gt;Still to be validated.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;tl;dr&lt;/strong&gt;
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Agent -&amp;gt; AgentCore Gateway -&amp;gt; your REST APIs / MCP Servers
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Not a silver bullet but it cuts out the MCP server grunt work if you have existing REST endpoints.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>mcp</category>
      <category>agentcore</category>
    </item>
    <item>
      <title>Dev Journal: Jot (Chrome Extension)</title>
      <dc:creator>Kat Padilla</dc:creator>
      <pubDate>Fri, 03 Apr 2026 07:45:00 +0000</pubDate>
      <link>https://dev.to/katpadi/dev-journal-jot-chrome-extension-3o07</link>
      <guid>https://dev.to/katpadi/dev-journal-jot-chrome-extension-3o07</guid>
      <description>&lt;h2&gt;
  
  
  Motivation
&lt;/h2&gt;

&lt;p&gt;I am working on a 14" personal laptop and I needed a fast, minimal notepad directly in the browser because because context switching is a pain. Existing options required accounts or had unnecessary features that I do not want.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;P.S. This is practically a side quest. I was working on a different project when I got bothered switching tabs and desktop spaces.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Goal/s
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Learn how to build a simple Chrome Extension&lt;/li&gt;
&lt;li&gt;Build a Chrome extension popup notepad&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Dev Log
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Browsed &lt;a href="https://developer.chrome.com/docs/extensions/get-started/tutorial/hello-world?ref=blog.katpadi.ph" rel="noopener noreferrer"&gt;https://developer.chrome.com/docs/extensions/get-started/tutorial/hello-world&lt;/a&gt; as a primer.&lt;/li&gt;
&lt;li&gt;Created a Chrome extension with &lt;code&gt;manifest.json&lt;/code&gt;, &lt;code&gt;popup.html&lt;/code&gt;, &lt;code&gt;popup.css&lt;/code&gt;, and &lt;code&gt;popup.js&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Implemented a textarea in &lt;code&gt;popup.html&lt;/code&gt; and wired it to &lt;code&gt;localStorage&lt;/code&gt; in &lt;code&gt;popup.js&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Added a clear button and hooked it to reset both UI state and stored data&lt;/li&gt;
&lt;li&gt;Added a character counter (just for the heck of it)&lt;/li&gt;
&lt;li&gt;Structured the UI into header, body, and footer sections in &lt;code&gt;popup.css&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Added a light/dark mode toggle and persisted the selected theme in &lt;code&gt;localStorage&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Implemented a "Copy all" button using the Clipboard API &lt;/li&gt;
&lt;li&gt;Wrote the Chrome Web Store listing fields:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;manifest.json&lt;/code&gt; description (105 chars)&lt;/li&gt;
&lt;li&gt;single-purpose statement&lt;/li&gt;
&lt;li&gt;privacy policy page (ikr?)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Packaged the extension into a zip&lt;/li&gt;

&lt;li&gt;Submitted the extension through the Chrome Web Store Developer Dashboard&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;This blog is harder than &lt;a href="https://github.com/katpadi/jot/blob/main/popup.js?ref=blog.katpadi.ph" rel="noopener noreferrer"&gt;popup.js&lt;/a&gt; itself because it simply does the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Load = restore note and theme from &lt;code&gt;localStorage&lt;/code&gt; on popup open&lt;/li&gt;
&lt;li&gt;Auto-save = persist note on every keystroke&lt;/li&gt;
&lt;li&gt;Count = update character count&lt;/li&gt;
&lt;li&gt;Copy = copy content to clipboard with feedback&lt;/li&gt;
&lt;li&gt;Clear = reset note and storage&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Result
&lt;/h2&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%2Ffwcn0xoyz6927c7svja0.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%2Ffwcn0xoyz6927c7svja0.png" width="800" height="387"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Currently, the extension has been packaged and submitted to the Chrome Web Store. Internet says it usually takes 2-5 days.&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%2F535ah066mr12y2e5qsow.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%2F535ah066mr12y2e5qsow.png" width="800" height="184"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I am already able to use it via Developer Tools. I just had to put it on Chrome Web Store and see what the process is like in case I want to build other extensions in the future.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lessons
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Chrome Web Store requires a privacy policy URL even if no data leaves the browser&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;localStorage&lt;/code&gt; in extensions is scoped to the extension origin, not the regular webpage context. So, inspecting extension storage requires opening DevTools on the popup, not the main page&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Github Repo:&lt;/strong&gt; &lt;a href="https://github.com/katpadi/jot/?ref=blog.katpadi.ph" rel="noopener noreferrer"&gt;https://github.com/katpadi/jot/&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Update: it's now published &lt;a href="https://chromewebstore.google.com/detail/jot/gogmghfcgficidobmgjbpfdejaaekgid?ref=blog.katpadi.ph" rel="noopener noreferrer"&gt;https://chromewebstore.google.com/detail/jot/gogmghfcgficidobmgjbpfdejaaekgid&lt;/a&gt;. Only took less than 24h to get approval.&lt;/p&gt;

</description>
      <category>googlechromeextensio</category>
      <category>dev</category>
      <category>weekendprojects</category>
    </item>
    <item>
      <title>Handling Errors Gracefully</title>
      <dc:creator>Kat Padilla</dc:creator>
      <pubDate>Thu, 05 Apr 2018 15:09:36 +0000</pubDate>
      <link>https://dev.to/katpadi/handling-errors-gracefully-2ced</link>
      <guid>https://dev.to/katpadi/handling-errors-gracefully-2ced</guid>
      <description>

&lt;p&gt;Sometimes it makes sense to treat errors as part of an application's "valid" flow of events. Meaning, expected errors should not necessarily make your code go crazy when random errors are raised.&lt;/p&gt;

&lt;p&gt;With that in mind, I created a way to implement some kind of "Result Object" by rescuing &lt;a href="https://ruby-doc.org/core-2.1.5/StandardError.html"&gt;StandardError&lt;/a&gt; instances and handling these errors gracefully.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Gracefully
  class &amp;lt;&amp;lt; self
    alias_method :handle, :new
  end

  attr_reader :error, :value

  def initialize
    @value = nil
    @error = nil
    begin
      @value = yield
    rescue =&amp;gt; e
      @error = e
    end
  end

  def success?
    error.nil?
  end

  def on_success
    return self unless success?
    result = yield(@value)
    return result if result.is_a?(Gracefully)
    Gracefully.handle { result }
  end

  def on_failure
    return self if success?
    result = yield(@error)
    return result if result.is_a?(Gracefully)
    Gracefully.handle { result }
  end
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/9aac974a760fc3f5f3a287bb75804de6"&gt;gracefully.rb&lt;/a&gt; &lt;a href="https://gist.githubusercontent.com/katpadi/9aac974a760fc3f5f3a287bb75804de6/raw/f2286a1645a66f7867db9abbd9ebf95113e46da3/gracefully.rb"&gt;view raw&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;In short, _ &lt;strong&gt;Gracefully&lt;/strong&gt; _ is a wrapper for a result object– it’s either a success value or an error object.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;result = Gracefully.handle { Order.find 999 }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In the example above, if order with id 999 does not exist, &lt;strong&gt;&lt;em&gt;result.success?&lt;/em&gt;&lt;/strong&gt; method will return false. Otherwise, true.&lt;/p&gt;

&lt;p&gt;If &lt;strong&gt;&lt;em&gt;result.success?&lt;/em&gt;&lt;/strong&gt;is true, &lt;em&gt;&lt;strong&gt;result.value&lt;/strong&gt;&lt;/em&gt; will contain the successful value. Otherwise, &lt;em&gt;&lt;strong&gt;result.error&lt;/strong&gt;&lt;/em&gt; will hold the error object itself.&lt;/p&gt;

&lt;p&gt;Whenever Gracefully.handle is called, it will return a Gracefully object. If you want to get the raw value, you can use &lt;em&gt;&lt;strong&gt;result.value&lt;/strong&gt;&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  More Usage
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;result = Gracefully.handle { ComplicatedService.new(foo, bar).process }
if result.success?
  # do success stuff
  use_value(result.value)
else
  # do failure stuff
  log_error(result.error)
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Chaining Usage
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Gracefully.handle { SomeComplicatedService.new.call }.on_success do |val|
  val.update!(column_name: 'stuff')
end

Gracefully.handle { SomeComplicatedService.new.call }.on_failure do |e|
  do_whatever_you_wish_with_the_error(e)
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;By using this, I can be resilient in handling errors and be able to recover from failures in the process flow.&lt;/p&gt;

&lt;p&gt;The post &lt;a href="http://blog.katpadi.ph/handling-error-gracefully/"&gt;Handling Errors Gracefully&lt;/a&gt; appeared first on &lt;a href="http://blog.katpadi.ph"&gt;KatPadi's Point&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;--&lt;br&gt;
Visit my website @ &lt;a href="http://katpadi.ph"&gt;http://katpadi.ph&lt;/a&gt;.&lt;/p&gt;


</description>
      <category>codes</category>
      <category>errors</category>
      <category>resultobject</category>
      <category>ruby</category>
    </item>
    <item>
      <title>What audiobook did you last listen to?</title>
      <dc:creator>Kat Padilla</dc:creator>
      <pubDate>Tue, 20 Mar 2018 12:14:58 +0000</pubDate>
      <link>https://dev.to/katpadi/what-audiobook-did-you-last-listen-to-460b</link>
      <guid>https://dev.to/katpadi/what-audiobook-did-you-last-listen-to-460b</guid>
      <description>&lt;p&gt;I listened to &lt;a href="https://www.audible.com/pd/Sci-Fi-Fantasy/The-Dispatcher-Audiobook/B01KKPH1VA" rel="noopener noreferrer"&gt;The Dispatcher&lt;/a&gt; by John Scalzi and it was awesome. My thoughts are &lt;a href="http://blog.katpadi.ph/listened-dispatcher-awesome/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;What did you last listen to? &lt;/p&gt;

</description>
      <category>discuss</category>
    </item>
    <item>
      <title>Hi, I'm katpadi</title>
      <dc:creator>Kat Padilla</dc:creator>
      <pubDate>Wed, 18 Jan 2017 03:52:16 +0000</pubDate>
      <link>https://dev.to/katpadi/hi-im-katpadi</link>
      <guid>https://dev.to/katpadi/hi-im-katpadi</guid>
      <description>&lt;p&gt;I have been coding for ~7 years.&lt;/p&gt;

&lt;p&gt;You can find me on Twitter as &lt;a href="https://twitter.com/katpadi" rel="noopener noreferrer"&gt;@katpadi&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I live in Manila at the moment.&lt;/p&gt;

&lt;p&gt;I work for a software company that helps brands increase their customer loyalty and engagement. &lt;/p&gt;

&lt;p&gt;I mostly program in Ruby currently. I used to write PHP. I am also a bit functional with Python. &lt;/p&gt;

&lt;p&gt;Nice to meet you.&lt;/p&gt;

</description>
      <category>introduction</category>
    </item>
    <item>
      <title>TIL: Redis Keyspace Notifications</title>
      <dc:creator>Kat Padilla</dc:creator>
      <pubDate>Thu, 12 Jan 2017 11:00:00 +0000</pubDate>
      <link>https://dev.to/katpadi/til-redis-keyspace-notifications-3eca</link>
      <guid>https://dev.to/katpadi/til-redis-keyspace-notifications-3eca</guid>
      <description>&lt;p&gt;For some reason, I was figuring out a way to be able to listen to Redis so I can fire callbacks when the Redis command or event  is encountered.&lt;/p&gt;

&lt;p&gt;I wanted to do something like:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;*&lt;em&gt;When a key gets removed from the sorted set, it will trigger a script that will notify a user. *&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Browsing online, I came across the so-called &lt;a href="https://redis.io/topics/notifications" rel="noopener noreferrer"&gt;&lt;strong&gt;Redis Keyspace Notifications&lt;/strong&gt;&lt;/a&gt;. It basically acts as a Pub/Sub mechanism that enables clients to subscribe to a Redis channel and receive “published” events whenever a Redis command or data alteration is encountered. The feature is available since version 2.8, apparently.&lt;/p&gt;

&lt;h2&gt;
  
  
  Diving in…
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi1.wp.com%2Fblog.katpadi.ph%2Fwp-content%2Fuploads%2F2017%2F01%2F1.1282587206.mark-diving-in.jpg%3Fresize%3D491%252C369" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi1.wp.com%2Fblog.katpadi.ph%2Fwp-content%2Fuploads%2F2017%2F01%2F1.1282587206.mark-diving-in.jpg%3Fresize%3D491%252C369" alt="Literally a person who is diving in. LOL"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Literally a person who is diving in. LOL&lt;/p&gt;

&lt;p&gt;The said notifications are enabled using the &lt;code&gt;notify-keyspace-events&lt;/code&gt; of redis.conf or via the &lt;strong&gt;CONFIG SET&lt;/strong&gt;. It is disabled by default.&lt;/p&gt;

&lt;p&gt;Setup will look something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Set it up.
$redis.config(:set, 'notify-keyspace-events', 'zE')
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/2eca03737eb188707cc79e9969185eee" rel="noopener noreferrer"&gt;redis-kesypace-event.rb&lt;/a&gt; &lt;a href="https://gist.githubusercontent.com/katpadi/2eca03737eb188707cc79e9969185eee/raw/213a4d7f0f2055ed2853ba3997b382d9da9ec61d/redis-kesypace-event.rb" rel="noopener noreferrer"&gt;view raw&lt;/a&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  zE… wut???
&lt;/h2&gt;

&lt;p&gt;zE looks so random if you weren’t briefed that each character in that string has a meaning.&lt;/p&gt;

&lt;p&gt;Below is the list of variable mapping for keyspace events:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi1.wp.com%2Fblog.katpadi.ph%2Fwp-content%2Fuploads%2F2017%2F01%2FScreen-Shot-2017-01-12-at-6.48.57-PM.png%3Fresize%3D752%252C294" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi1.wp.com%2Fblog.katpadi.ph%2Fwp-content%2Fuploads%2F2017%2F01%2FScreen-Shot-2017-01-12-at-6.48.57-PM.png%3Fresize%3D752%252C294"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For my particular case, I needed to use “&lt;code&gt;zE&lt;/code&gt;” string because I want to catch the name of the key (and not the name of the event) when &lt;code&gt;zrem&lt;/code&gt;, which is a sorted set command, is encountered.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keyspace v.s. Keyevent
&lt;/h2&gt;

&lt;p&gt;Let’s cut to the chase! Use keyspace if you want to receive the &lt;strong&gt;name of the event&lt;/strong&gt;. Use keyevent if you want to receive the &lt;strong&gt;name of the key&lt;/strong&gt;.&lt;/p&gt;

&lt;h6&gt;
  
  
  &lt;em&gt;TILception (TIL within a TIL): If you want to enable all events, use “KEA”.&lt;/em&gt;
&lt;/h6&gt;

&lt;p&gt;So, here’s an example of what I played around with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Subscriber
$redis.psubscribe(' __keyevent@*__ :zrem') do |on|
  on.pmessage do |pattern, channel, message|
    puts "==== AFTER zrem EVENT ====="
    # Available things:
    puts "pattern: #{pattern}"
    puts "channel: #{channel}"
    puts "message: #{message}"
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/2eca03737eb188707cc79e9969185eee" rel="noopener noreferrer"&gt;redis-kesypace-event.rb&lt;/a&gt; &lt;a href="https://gist.githubusercontent.com/katpadi/2eca03737eb188707cc79e9969185eee/raw/213a4d7f0f2055ed2853ba3997b382d9da9ec61d/redis-kesypace-event.rb" rel="noopener noreferrer"&gt;view raw&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;As I told earlier, I wanted to catch the “key” as a message and not the “event”. So, the message variable in the above code will output the key.&lt;/p&gt;

&lt;p&gt;Now, in your redis-cli, if you try to prepare a sorted set by using &lt;code&gt;zadd&lt;/code&gt; and then doing a &lt;code&gt;zrem&lt;/code&gt;, you will see the output in your console.&lt;/p&gt;

&lt;p&gt;=)&lt;/p&gt;

&lt;p&gt;Now it’s time for me to send that notification!&lt;/p&gt;

&lt;p&gt;The post &lt;a href="http://blog.katpadi.ph/til-redis-keyspace-notifications/" rel="noopener noreferrer"&gt;TIL: Redis Keyspace Notifications&lt;/a&gt; appeared first on &lt;a href="http://blog.katpadi.ph" rel="noopener noreferrer"&gt;KatPadi's Point&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>codes</category>
      <category>tech</category>
      <category>thoughts</category>
      <category>rediscallback</category>
    </item>
    <item>
      <title>Git: Squash Commits</title>
      <dc:creator>Kat Padilla</dc:creator>
      <pubDate>Mon, 12 Dec 2016 10:52:14 +0000</pubDate>
      <link>https://dev.to/katpadi/git-squash-commits-48c6</link>
      <guid>https://dev.to/katpadi/git-squash-commits-48c6</guid>
      <description>&lt;p&gt;With git it’s possible to &lt;a href="https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History" rel="noopener noreferrer"&gt;squash&lt;/a&gt; previous commits into one before sharing them with others.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1
&lt;/h2&gt;

&lt;p&gt;For example you want to squash your last 3 commits:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git rebase -i HEAD~3&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;On the other hand, if you want to just simply squash all the unpushed commits:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git rebase -i origin/master&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If you have many commits and want to start from a certain commit:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git rebase -i&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Any of the command above will prompt open your editor with something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pick a92f09 Added new feature X
pick ca9f90a Some other stuff I did
pick d18a6h1 More stuff I did
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will show up in your editor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pick a92f09 Added new feature X
squash ca9f90a Some other stuff I did
squash d18a6h1 More stuff I did
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: If you don’t have an editor defined in your config, you will encounter &lt;code&gt;Could not execute editor&lt;/code&gt;. Just do &lt;code&gt;git config --global core.editor /usr/bin/vim&lt;/code&gt; for you to be able to proceed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2
&lt;/h2&gt;

&lt;p&gt;Next, we can configure git on what to do with the commits. Let’s say, I want to keep commit a92f09. Git squash-ing the following two commits into the first one will leave us with one single commit with all the commits in it. To do that, change your file to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pick a92f09 Added new feature X
squash ca9f90a Some other stuff I did
squash d18a6h1 More stuff I did
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save and exit.&lt;/p&gt;

&lt;p&gt;That’s it. Git squash is especially useful if you want to wrap up “all in a day’s work” or if you want to have a clean and concise git history.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;Use &lt;code&gt;git rebase -i origin/master&lt;/code&gt; and replace “pick” on the second and succeeding commits with “squash”.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi1.wp.com%2Fblog.katpadi.ph%2Fwp-content%2Fuploads%2F2016%2F12%2Ftemp_quash.jpg%3Fresize%3D267%252C178" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi1.wp.com%2Fblog.katpadi.ph%2Fwp-content%2Fuploads%2F2016%2F12%2Ftemp_quash.jpg%3Fresize%3D267%252C178" alt="git squash?"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The post &lt;a href="http://blog.katpadi.ph/git-squash/" rel="noopener noreferrer"&gt;Git: Squash Commits&lt;/a&gt; appeared first on &lt;a href="http://blog.katpadi.ph" rel="noopener noreferrer"&gt;KatPadi's Point&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>myworklog</category>
      <category>git</category>
      <category>gitrebase</category>
      <category>gitsquash</category>
    </item>
  </channel>
</rss>
