<?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: Shipyard DevRel</title>
    <description>The latest articles on DEV Community by Shipyard DevRel (@shipyard).</description>
    <link>https://dev.to/shipyard</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F688300%2F3108e315-1db4-47ee-90e9-88dfc72c9ca5.png</url>
      <title>DEV Community: Shipyard DevRel</title>
      <link>https://dev.to/shipyard</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/shipyard"/>
    <language>en</language>
    <item>
      <title>Claude Code tokens: what they are and how they're counted</title>
      <dc:creator>Shipyard DevRel</dc:creator>
      <pubDate>Mon, 30 Mar 2026 21:54:37 +0000</pubDate>
      <link>https://dev.to/shipyard/claude-code-tokens-what-they-are-and-how-theyre-counted-4l4f</link>
      <guid>https://dev.to/shipyard/claude-code-tokens-what-they-are-and-how-theyre-counted-4l4f</guid>
      <description>&lt;p&gt;You might have noticed that Claude Code tracks usage via "tokens" consumed, which you've probably seen from the &lt;code&gt;/cost&lt;/code&gt; or &lt;code&gt;/context&lt;/code&gt; commands, your Anthropic dash, or just in Claude convos.&lt;/p&gt;

&lt;p&gt;Tokens are the constant, foundational unit that Claude uses to read and generate text. They're not exclusive to Claude, as Claude tokens are the same as &lt;a href="https://www.geeksforgeeks.org/nlp/nlp-how-tokenizing-text-sentence-words-works/" rel="noopener noreferrer"&gt;NLP tokens&lt;/a&gt;, which are what LLMs use to process input and generate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tokenization in NLP
&lt;/h2&gt;

&lt;p&gt;LLMs break text content down into tokens, which are chunks of text that might be somewhere between a character and a full word long. Depending on your tokenizer, the word "programmatically" could be broken down into tokens as "program" + "matically", or as a whole word (alternatively, &lt;a href="https://smltar.com/tokenization#character-tokens" rel="noopener noreferrer"&gt;character tokenization&lt;/a&gt; would break it down by letter, to catch unique spellings and typos). You can see how OpenAI's models tokenize text with &lt;a href="https://platform.openai.com/tokenizer" rel="noopener noreferrer"&gt;this webapp&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Each token has a next-most-likely token, based on how that token has been used in the training data. LLMs take input text, and output a series of tokens that are statistically likely to follow the tokenized input.&lt;/p&gt;

&lt;p&gt;Punctuation, whitespace, and code syntax are included in tokens, and their token length is shorter than that of written copy. Every LLM has a set context window, which is the memory limit of how many tokens it can hold at a time (most Claude models hold ~200k). When you exceed the context window, earlier tokens will get dropped.&lt;/p&gt;

&lt;p&gt;So when you're using Claude Code, keep in mind that code is more token-dense than natural language. And languages like Python are more token-efficient than Rust or C++.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Claude tokenizes text
&lt;/h2&gt;

&lt;p&gt;Claude uses a tokenizer trained specifically on its training data, so strings will be tokenized differently from other models like GPT-5. Claude's token length averages out to about 4 letters per token, and 1.5 tokens per word. Token length is shorter for code snippets, e.g. &lt;code&gt;()&lt;/code&gt; or &lt;code&gt;{&lt;/code&gt; will each equal one token.&lt;/p&gt;

&lt;p&gt;When you prompt CC with an input, it doesn't just tokenize your message alone: it'll process that along with the conversation history, loaded files, system prompts, command outputs, etc. As Claude processes more context, it consumes more tokens since this "input" compounds. Longer sessions will start to drain usage faster as they go on because of this.&lt;/p&gt;

&lt;h2&gt;
  
  
  Input vs. output tokens (and cache tokens)
&lt;/h2&gt;

&lt;p&gt;Claude distinguishes between input tokens (e.g. what you submit to the model, as well as history + context) and output tokens (the text that it generates). These are tracked separately and have different pricing rates.&lt;/p&gt;

&lt;p&gt;Claude prices output tokens higher than input tokens. With Claude Sonnet, for example, output tokens cost ~5x more per million than input tokens. So when Claude writes 300 lines of code, it'll be much more pricey vs. when it reads 300 lines and generates a short answer. Or when CC reads in your entire codebase, it won't cost as much as one-shot generating a codebase of a comparable size.&lt;/p&gt;

&lt;p&gt;There's a third type of token class: cache tokens. CC supports &lt;a href="https://platform.claude.com/docs/en/build-with-claude/prompt-caching" rel="noopener noreferrer"&gt;prompt caching&lt;/a&gt;, which lets repeated context (a long system prompt, a codebase snapshot, etc.) get stored then reused at a much lower token price rate. So adding project context to your system prompt and &lt;code&gt;CLAUDE.md&lt;/code&gt; will help keep usage lower over time (vs. repeating the same instructions often in a prompt).&lt;/p&gt;

&lt;h2&gt;
  
  
  How to track your token usage
&lt;/h2&gt;

&lt;p&gt;Here's a detailed &lt;a href="https://shipyard.build/blog/claude-code-track-usage/" rel="noopener noreferrer"&gt;guide on tracking Claude Code tokens&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you're using Claude via the API, you can view your token consumption, costs by model, and usage over time in the &lt;a href="https://platform.claude.com/" rel="noopener noreferrer"&gt;Claude Console&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Running the &lt;code&gt;/cost&lt;/code&gt; command during a Claude Code session will show token usage for your current session, with respect to cost. If you're on a Pro or Max subscription and not the API, &lt;code&gt;/cost&lt;/code&gt; reflects what you &lt;em&gt;would&lt;/em&gt; have paid via API. You can also run &lt;code&gt;/context&lt;/code&gt; to see how many tokens are currently filling your context window.&lt;/p&gt;

&lt;p&gt;Third-party tools can give you good metrics on your usage. &lt;a href="https://github.com/ryoppippi/ccusage" rel="noopener noreferrer"&gt;ccusage&lt;/a&gt; is a lightweight CLI tool that reads and analyzes Claude's local JSONL files for token metrics. You can run and install it with &lt;code&gt;npx ccusage@latest&lt;/code&gt;. If you want something more real-time, you can run &lt;a href="https://github.com/Maciek-roboblog/Claude-Code-Usage-Monitor" rel="noopener noreferrer"&gt;Claude-Code-Usage-Monitor&lt;/a&gt; to track live token consumption and burn rate. It'll also predict when you're likely to hit your limits.&lt;/p&gt;

&lt;h2&gt;
  
  
  Environments for Claude Code
&lt;/h2&gt;

&lt;p&gt;When you're developing with Claude Code, you'll want to make sure that every new feature is tested extensively in a secure, isolated environment. Ephemeral environments pair beautifully with CC: you can spin up an environment automatically based on a branch/PR, run tests, do QA, push patches, and then merge once you've determined it's ready.&lt;/p&gt;

&lt;p&gt;Shipyard is a plug-and-play ephemeral environment solution for devs using Claude Code. Claude can interact with the environments on its own via &lt;a href="https://docs.shipyard.build/mcp" rel="noopener noreferrer"&gt;MCP&lt;/a&gt;/&lt;a href="https://docs.shipyard.build/cli" rel="noopener noreferrer"&gt;CLI&lt;/a&gt; (pull logs, get each live URL, visit the environments with &lt;a href="https://github.com/microsoft/playwright-mcp" rel="noopener noreferrer"&gt;Playwright MCP&lt;/a&gt;, etc). &lt;a href="https://shipyard.build/signup" rel="noopener noreferrer"&gt;Try it free for 30 days&lt;/a&gt; and see how much faster your dev/test loop gets.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
    </item>
    <item>
      <title>Devoting December to developer enrichment</title>
      <dc:creator>Shipyard DevRel</dc:creator>
      <pubDate>Mon, 22 Dec 2025 22:05:35 +0000</pubDate>
      <link>https://dev.to/shipyard/devoting-december-to-developer-enrichment-l94</link>
      <guid>https://dev.to/shipyard/devoting-december-to-developer-enrichment-l94</guid>
      <description>&lt;p&gt;Engineering teams spend so much time during the year talking about developer productivity. December is a difficult time to keep those metrics up anyway, so why not use the holiday stretch to catch up on your skills and learn new things?&lt;/p&gt;

&lt;h2&gt;
  
  
  December for engineers
&lt;/h2&gt;

&lt;p&gt;December is perhaps the most inconsistent month of the year, work-wise. Some employees are taking PTO to travel and visit family during various times of the month, and the last week (or two) might be company-wide break.&lt;/p&gt;

&lt;p&gt;This makes it nearly impossible to operate to the same goals expected during any other month. Plus, there’s a solid amount of review/administrative work that needs to happen (particularly retrospectives and Q1 planning).&lt;/p&gt;

&lt;p&gt;Under these conditions, December isn’t a fulfilling work month for engineers. Yes, the workload is lighter, but the actual culprit is the &lt;em&gt;quality&lt;/em&gt; of tasks. &lt;/p&gt;

&lt;h2&gt;
  
  
  Why set aside time to upskill?
&lt;/h2&gt;

&lt;p&gt;Many people have a never-ending list of new technologies that they want to learn, but rarely are able to get around to. The software space moves so fast, and there’s a constant flow of new tools (especially those that you aren’t using and/or won’t use on the job). Setting aside time to explore these is very much worth it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Learning new things is good for your brain, and can improve your problem-solving skills and make you happier&lt;/li&gt;
&lt;li&gt;Doing something different during your 9-5 is a good remedy for the EoY burnout&lt;/li&gt;
&lt;li&gt;You’re going to be on your computer anyway, and it’s likely your work responsibilities have wound down. This is a great opportunity to repurpose that time&lt;/li&gt;
&lt;li&gt;You might pick up a new tool/technology that positively impacts your work&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Most of us don’t have time to upskill off the clock, and that can be a real disadvantage in the tech field. There’s a lot you can accomplish during the most prime working hours of your day, and when it’s work that you find engaging/challenging, it can help you re-invigorate before your holiday break. Otherwise, if you’re not engaged during the last week or two, you might dread going back in January even more.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keeping your mind sharp
&lt;/h2&gt;

&lt;p&gt;December leaves too many devs bored and unfulfilled. Most orgs have a code freeze, so there are fewer (impactful) things to work on. Support and basic maintenance tasks get dull after awhile, which makes it all too easy to mentally check out. &lt;/p&gt;

&lt;p&gt;Getting your manager’s encouragement to use this time to learn can help you genuinely enjoy the last couple weeks of work, rather than counting down the hours until break. &lt;/p&gt;

&lt;p&gt;If there isn’t anything immediately top-of-mind, you could try one of these topics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Contribute to an open source project&lt;/li&gt;
&lt;li&gt;Learn a new devtool&lt;/li&gt;
&lt;li&gt;Take an online course&lt;/li&gt;
&lt;li&gt;Try your hand at Advent of Code&lt;/li&gt;
&lt;li&gt;Create a hobby project with a new stack&lt;/li&gt;
&lt;li&gt;Try a totally different function (UX, platform, design, etc)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This could also be a good opportunity to document your learnings with blog posts. Doing so can help you remember what you learned, and help jog your memory of any challenges you encountered.&lt;/p&gt;

&lt;h2&gt;
  
  
  How can you implement this as a manager?
&lt;/h2&gt;

&lt;p&gt;As a manager, you obviously want your team to thrive. During busy years, there might be fewer opportunities for devs to learn and grow outside their assignments. So if you’re lucky enough to see tasks wind down in December, you can repurpose this time.&lt;/p&gt;

&lt;p&gt;The way you go about this really comes down to each dev’s learning style. Some people thrive with structure, while others prefer to self-manage. You probably are familiar with how each team member excels, so you can make it as rigid or as flex as they need. But as far as rigidity goes, you’ll want to leave this at least somewhat open-ended, so it feels less like work, and more like enrichment. You can step in for accountability, but you shouldn’t have to track their “progress”. It won’t quite work if your devs aren’t excited about what they’re learning, which will also do nothing to improve burnout. &lt;/p&gt;

&lt;p&gt;You can work with your team and listen as they set their own goals. Listen to what technologies they want to learn, and what they want to accomplish with them. If you know of any resources, share them. And if a particular dev is overwhelmed with the sheer amount of options they have, suggest something more guided, like an online course or Advent of Code. &lt;/p&gt;

&lt;h2&gt;
  
  
  Happy holidays to you and your team
&lt;/h2&gt;

&lt;p&gt;So much is in flux during December, especially during the second half. Engineering managers don’t usually expect much in the way of productivity, so why not use this time for upskilling/education/things that get left on the back burner otherwise?&lt;/p&gt;

&lt;p&gt;Doing so can be a great refresher and an answer to end-of-year burnout. Help your teammates remember &lt;em&gt;why&lt;/em&gt; they were passionate about software in the first place.&lt;/p&gt;

</description>
      <category>learning</category>
      <category>productivity</category>
      <category>programming</category>
      <category>development</category>
    </item>
    <item>
      <title>How to track Claude Code usage + analytics</title>
      <dc:creator>Shipyard DevRel</dc:creator>
      <pubDate>Mon, 17 Nov 2025 20:26:15 +0000</pubDate>
      <link>https://dev.to/shipyard/how-to-track-claude-code-usage-analytics-52ak</link>
      <guid>https://dev.to/shipyard/how-to-track-claude-code-usage-analytics-52ak</guid>
      <description>&lt;p&gt;Now that you’ve gotten into the habit of working with &lt;a href="https://claude.ai/code" rel="noopener noreferrer"&gt;Claude Code&lt;/a&gt;, you’re probably curious to see how efficiently you’re using it. For example, do you know how many tokens it’s taking you to complete a ticket on average? Since Claude tokens can run out and will reset after 5 hours, you might want to see how much you’re pushing it to the limit.&lt;/p&gt;

&lt;p&gt;We’ve tried three different ways to track our Claude Code usage. Here’s what we found.&lt;/p&gt;

&lt;h2&gt;
  
  
  Option 1 (the classic way): Check the Anthropic Console
&lt;/h2&gt;

&lt;p&gt;If you’re using the &lt;a href="https://docs.anthropic.com/en/api/overview" rel="noopener noreferrer"&gt;Anthropic API&lt;/a&gt; for Claude Code access (instead of through a Pro or Max plan), you can track your usage through the &lt;a href="https://console.anthropic.com" rel="noopener noreferrer"&gt;Anthropic Console&lt;/a&gt;. This is useful for devs and orgs who are doing the “pay as you go” approach, because your number of tokens consumed is directly correlated to how much you’re spending.&lt;/p&gt;

&lt;p&gt;If you’re a manager, you can see usage trends for your whole team, and get the data you need to find how Claude Code is impacting developer productivity. You’ll be able to see how often you/others accept Claude’s suggested changes. Anthropic suggests using this as a way to measure your org’s Claude Code adoption, as well.&lt;/p&gt;

&lt;h2&gt;
  
  
  Option 2 (view within your session): /context slash command
&lt;/h2&gt;

&lt;p&gt;You can also view your current usage directly from a Claude Code session by running the &lt;code&gt;/context&lt;/code&gt; slash command.&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%2Fg8kchd62zgsggwx8wwmj.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%2Fg8kchd62zgsggwx8wwmj.png" alt="Claude Code context slash command" width="800" height="286"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This will show you how many tokens you've consumed, how many you have available, and break down token usage by category. It'll also show you a detailed view of how individual actions (including MCP tool uses) have consumed tokens.&lt;/p&gt;

&lt;h2&gt;
  
  
  Option 3 (view historical usage): ccusage
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/ryoppippi/ccusage" rel="noopener noreferrer"&gt;ccusage&lt;/a&gt; is a CLI-based tool that lets you view usage by date, session, or project. We really liked using this tool for seeing how our usage was divided across repos (e.g. which ones did we rely on Claude more for?).&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%2F11zdqz93q5622zy4u7it.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%2F11zdqz93q5622zy4u7it.png" alt="ccusage tracking token spend for Claude Code" width="800" height="339"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It works by reading + analyzing Claude’s local JSONL files. This is super helpful if you have a Pro or Max plan, since you’re paying a flat rate per month and can’t track this via the Anthropic Console.&lt;/p&gt;

&lt;p&gt;One cool thing about ccusage is that it’s so small you don’t need to fully install it, you can just run the &lt;code&gt;npx&lt;/code&gt; command with whichever args you want to filter by:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx ccusage@latest report daily
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also install it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; ccusage
ccusage report daily &lt;span class="nt"&gt;--since&lt;/span&gt; 20250801
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since it’s a CLI tool, you can ask Claude Code to run ccusage and retrieve info for specific search params:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Hey Claude, use ccusage to find my analytics for the RecipeBook project between July 3rd and July 7th.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The only limitation is that ccusage can’t show your current, real-time Claude Code analytics. If this is something you want, check out the next tool in our list.&lt;/p&gt;

&lt;h2&gt;
  
  
  Option 4 (view real-time usage): Claude-Code-Usage-Monitor
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/Maciek-roboblog/Claude-Code-Usage-Monitor?tab=readme-ov-file#-installation" rel="noopener noreferrer"&gt;Claude-Code-Usage-Monitor&lt;/a&gt; is another CLI-based tool for tracking how you use Claude Code. Unlike ccusage, this one gives you a real-time chart of your token consumption, cost estimate, and predictions about how long it’ll take for you to hit your limits.&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%2F25okr23swuowkacpr85x.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%2F25okr23swuowkacpr85x.png" alt="Claude Code usage monitor" width="800" height="481"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can install it with pip or uv and run it with the &lt;code&gt;cmonitor&lt;/code&gt; command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;claude-monitor
cmonitor
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run it while you’re using Claude in a different window, and see it update live as Claude generates. Like ccusage, this pulls from Claude’s local data. &lt;/p&gt;

&lt;p&gt;You can see your historical usage in table view by including a timeframe:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cmonitor &lt;span class="nt"&gt;--view&lt;/span&gt; monthly
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Understanding Claude's session model
&lt;/h2&gt;

&lt;p&gt;If you want to best plan out your Claude sessions, you’ll want to understand your constraints. Claude’s tokens are granted by plan based on overall server load, so on busier days you’ll get fewer. &lt;/p&gt;

&lt;p&gt;If you’re not using the API for pay-as-you-go Claude access, you’ll want to choose the Claude tier that works best for you. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pro:&lt;/strong&gt; for a medium-high coding workload. Expect to use continuously for smaller code changes, and as a supplement to your own coding. $20/month&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Max5:&lt;/strong&gt; for an intense coding workload. 5x the token allowance of Pro. Opus access. $100/month&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Max20:&lt;/strong&gt; for near-autonomous, nonstop, heavy development workloads with multiple sessions/agents. Significantly larger context window. 20x the token allowance of Pro. Opus access. $200/month&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sessions kick off as soon as you send your first message, and last five hours.&lt;/p&gt;

&lt;p&gt;It’s most efficient (and guarantees better outputs) if you start different sessions for different tasks.&lt;/p&gt;

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

&lt;p&gt;We found the &lt;code&gt;/context&lt;/code&gt; slash command, ccusage, and Claude-Code-Usage-Monitor were easy to use, and helped us make sense of our Claude metrics. This was helpful for tracking our own developer productivity, as well as seeing how Claude impacted our work styles. &lt;/p&gt;

&lt;p&gt;If you’re using the Pro or Max tiers, you won’t be able to see this info in the Anthropic Console. We suggest using tools to supplement each other: &lt;code&gt;/context&lt;/code&gt; to get a good summary by category, ccusage to view your usage trends, and Claude-Code-Usage-Monitor to see your live token consumption and predictions.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Using Claude Code? Give your agents ephemeral environments. They can deploy the code they write, pull logs, find + fix bugs, all with little-to-no human intervention. &lt;a href="https://shipyard.build/signup" rel="noopener noreferrer"&gt;Try it free for 30 days&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>performance</category>
      <category>agents</category>
    </item>
    <item>
      <title>The Shipyard MCP Server: Manage environments with AI agents</title>
      <dc:creator>Shipyard DevRel</dc:creator>
      <pubDate>Fri, 14 Nov 2025 22:21:57 +0000</pubDate>
      <link>https://dev.to/shipyard/the-shipyard-mcp-server-manage-environments-with-ai-agents-2249</link>
      <guid>https://dev.to/shipyard/the-shipyard-mcp-server-manage-environments-with-ai-agents-2249</guid>
      <description>&lt;p&gt;We’re excited to announce the &lt;a href="https://github.com/shipyard/shipyard-cli?tab=readme-ov-file#model-context-protocol-mcp-integration" rel="noopener noreferrer"&gt;beta release of our MCP server&lt;/a&gt;. Now you can loop your agents into environment management, and give them access/context to run tests, tail environment logs, start/stop environments, and debug remote issues.&lt;/p&gt;

&lt;p&gt;The MCP server is an extension of the Shipyard CLI, so if you're already set up auth, you won't need to add your token again. &lt;/p&gt;

&lt;h4&gt;
  
  
  Installing the Shipyard CLI/MCP
&lt;/h4&gt;

&lt;p&gt;&lt;em&gt;(Skip this step if you already have the Shipyard CLI installed)&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew tap shipyard/tap
brew &lt;span class="nb"&gt;install &lt;/span&gt;shipyard
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Claude Code
&lt;/h4&gt;

&lt;p&gt;With API token and org name:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude mcp add shipyard &lt;span class="nt"&gt;--env&lt;/span&gt; &lt;span class="nv"&gt;SHIPYARD_API_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your-token-here &lt;span class="nt"&gt;--env&lt;/span&gt; &lt;span class="nv"&gt;SHIPYARD_ORG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your-org-name &lt;span class="nt"&gt;--&lt;/span&gt; shipyard mcp serve
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If already configured with CLI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude mcp add shipyard &lt;span class="nt"&gt;--&lt;/span&gt; shipyard mcp serve
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Codex CLI
&lt;/h4&gt;

&lt;p&gt;Edit &lt;code&gt;~/.codex/config.toml&lt;/code&gt; and add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;mcp_servers.shipyard&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="s"&gt;command = "shipyard"&lt;/span&gt;
&lt;span class="s"&gt;args = ["mcp", "serve"]&lt;/span&gt;
&lt;span class="s"&gt;env = { "SHIPYARD_API_TOKEN" = "your-token-here", "SHIPYARD_ORG" = "your-org-name" }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;(Contact us at &lt;a href="mailto:support@shipyard.build"&gt;support@shipyard.build&lt;/a&gt; if you need API access).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="/images/blog/agents/mcp.png" class="article-body-image-wrapper"&gt;&lt;img src="/images/blog/agents/mcp.png" alt="Using the MCP to connect to ephemeral environments"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;Our users have been using the MCP server to add more capabilities to their agent dev loops:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Writing and improving E2E tests:&lt;/strong&gt; your agent will use your codebase, the Shipyard MCP, and the &lt;a href="https://github.com/microsoft/playwright-mcp" rel="noopener noreferrer"&gt;Playwright MCP&lt;/a&gt; to study your app and improve existing tests&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sandboxes for rapid prototyping:&lt;/strong&gt; generate code with your agent and instantly see that in a live env, then pull logs to iterate/improve features&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Live code reviews:&lt;/strong&gt; use the Shipyard MCP to get an env link, then use Playwright MCP to gather info about the feature, cross reference with the codebase&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Start building!
&lt;/h2&gt;

&lt;p&gt;If you're a dev building with agents, we highly encourage you to &lt;a href="https://docs.shipyard.build/mcp" rel="noopener noreferrer"&gt;try it out&lt;/a&gt; today. It's 100% &lt;a href="https://github.com/shipyard/shipyard-cli?tab=readme-ov-file#model-context-protocol-mcp-integration" rel="noopener noreferrer"&gt;open source&lt;/a&gt;, so feel free to fork it, open a PR, or use it to help you build your own MCP server.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;a href="https://shipyard.build/signup" rel="noopener noreferrer"&gt;(Sign up for a 30-day free Shipyard trial if you haven’t yet).&lt;/a&gt;&lt;/em&gt; &lt;/p&gt;

&lt;p&gt;We're curious to hear how you’re using it to build and test faster. Write us at &lt;a href="mailto:hello@shipyard.build"&gt;hello@shipyard.build&lt;/a&gt; to share your thoughts. Any and all feedback is super valuable for us during the beta.&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>ai</category>
      <category>agents</category>
    </item>
    <item>
      <title>Pair programming with Claude Code: using output styles</title>
      <dc:creator>Shipyard DevRel</dc:creator>
      <pubDate>Thu, 09 Oct 2025 17:43:52 +0000</pubDate>
      <link>https://dev.to/shipyard/pair-programming-with-claude-code-using-output-styles-1l5j</link>
      <guid>https://dev.to/shipyard/pair-programming-with-claude-code-using-output-styles-1l5j</guid>
      <description>&lt;p&gt;As a developer, you've gone into software likely because you &lt;em&gt;enjoy&lt;/em&gt; writing code. This isn't a chore for you, and you get some degree of fulfillment from it. If you're reading this, you're probably using agentic devtools to improve your productivity, and take away some of the toil that comes with dev work.&lt;/p&gt;

&lt;p&gt;Why should agents get to do all the fun parts of software dev, like writing code? &lt;a href="https://docs.anthropic.com/en/docs/claude-code" rel="noopener noreferrer"&gt;Claude Code&lt;/a&gt; (the world's favorite AI coding agent) has a feature that allows you to make agentic dev more &lt;em&gt;active.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Here's how you can write code &lt;em&gt;alongside&lt;/em&gt; Claude Code, instead of through pure natural language prompts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why pair program with AI agents?
&lt;/h2&gt;

&lt;p&gt;Agents can generate code incredibly fast, and at volumes that are tough for humans to truly digest. Many devs end up turning off their brains at a certain point, because understanding the agent's code is &lt;em&gt;much slower&lt;/em&gt; than prompting fast and getting a working result.&lt;/p&gt;

&lt;p&gt;This leads to devs accepting agentic code suggestions blindly. It's a slippery slope for sure: if 90% of an LLM's suggestions are good, why should you have to sift through all of them with a fine-toothed comb, especially if you hardly find anything off? Then next thing you know, your agent accidentally corrupts your database or changes your file permissions.&lt;/p&gt;

&lt;p&gt;Pair programming with an agent keeps you, as the developer, engaged and in the driver's seat. You're actively thinking through every choice, being intentional. It's more akin to the mindset you get into when you're 100% writing code.&lt;/p&gt;

&lt;p&gt;Plus, AI agents are good for many things beyond picking up coding tickets. Thanks to their LLMs' wide knowledge bases, they can explain things pretty well, and pick up on niche software patterns. They can step into that "pair" role and guide you. This brings them closer to human-human pair programming&lt;/p&gt;

&lt;h2&gt;
  
  
  Claude Code output styles
&lt;/h2&gt;

&lt;p&gt;In August 2025, Anthropic introduced a new feature for changing how Claude Code interacts with a user. &lt;a href="https://docs.anthropic.com/en/docs/claude-code/output-styles" rel="noopener noreferrer"&gt;Output styles&lt;/a&gt; can help extend CC beyond its popular use cases, and Anthropic suggests this can make CC act as any kind of agent (with the same core read/write/execute/list capabilities).&lt;/p&gt;

&lt;p&gt;An output style for Claude Code is functionally the same as a system prompt. Claude's default output style is concise, and targeted mainly at solving software engineering tasks.&lt;/p&gt;

&lt;p&gt;CC includes two other built-in output styles, which are (in our opinion) more conducive to pair programming.&lt;/p&gt;

&lt;h3&gt;
  
  
  Explanatory output style
&lt;/h3&gt;

&lt;p&gt;To set: &lt;code&gt;/output-style explanatory&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Claude Code's explanatory mode is similar to the default system prompt, but offers educational insights along the way. This is a good mode for newer devs who don't want CC to do all the thinking for them, and are hoping to stay engaged during agentic dev tasks.&lt;/p&gt;

&lt;p&gt;CC will add little "insight" blocks within its responses. These are kind of like pro tips, or just extra background info. Since default CC is concise, this is helpful for getting more complete, detailed answers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sample prompt:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;look at the CLI docs, and tell me what can be improved in the scope of DevEx&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CC explanatory mode response (excerpt):&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;...&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;Strategic Long-term Enhancements&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;7. **Progressive disclosure with expandable sections**&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;8. **Integration examples with popular IDEs and tools**&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;9. **Video walkthroughs for complex workflows**&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;10. **Interactive CLI tutorial or guided setup**&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;★ Insight ─────────────────────────────────────&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;The current documentation is comprehensive but lacks the user-centric&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;design principles that make modern developer tools delightful to use. The&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;biggest opportunities are in restructuring content around workflows and&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;reducing friction in the getting-started experience.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;──────────────────────────────────────────&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Learning output style
&lt;/h3&gt;

&lt;p&gt;To set: &lt;code&gt;/output-style learning&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Learning mode is more interactive than default or explanatory mode. It gives the user small programming tasks to complete during development, so they can contribute code. It's really beneficial for junior engineers looking for a pair programming setup, as it will break down tasks, assign them, and then give feedback on the completed snippet.&lt;/p&gt;

&lt;p&gt;This was our favorite CC output style, since it let us pick up fun coding tasks and walked us through the why/how of every action.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sample prompt:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;look at the CLI docs, and tell me what can be improved in the scope of DevEx&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CC learning mode response (excerpt):&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;Your Task:&lt;/code&gt;&lt;/strong&gt; In docs/CLI.mdx, create a new "Quick Start" section`&lt;/p&gt;

&lt;p&gt;&lt;code&gt;that should appear right after line 13 (after the opening description).&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Look for TODO(human). This section should provide developers with the&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;fastest possible path from installation to their first successful CLI&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;interaction.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;Guidance:&lt;/code&gt;&lt;/strong&gt; Consider what a developer most wants to accomplish when they`&lt;/p&gt;

&lt;p&gt;&lt;code&gt;first install the CLI - probably seeing their environments and confirming&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;everything works. Think about the psychological impact of early success&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;vs. getting stuck on setup details. The section should be concise (3-5&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;commands max) and include a verification step that shows success.&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating your own custom output style
&lt;/h2&gt;

&lt;p&gt;Claude Code is super customizable, and most of this can be done via natural language in Markdown files. You can create your own output style (which is a system prompt for CC) by running:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/output-style:new [name] [verbose description]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Remember, everything that CC knows about software engineering lives in the default output style. You'll need to re-enlighten it here if you want it to be a strong software engineering pair.&lt;/p&gt;

&lt;p&gt;Once you provide a description of what output style you'd like, Claude will generate a markdown file, inferring what other characteristics it should have. You can find it in your &lt;code&gt;~/.claude/output-styles/&lt;/code&gt; directory. You'll want to tweak this to fit what you had in mind.&lt;/p&gt;

&lt;h2&gt;
  
  
  Changing Claude Code's system prompt
&lt;/h2&gt;

&lt;p&gt;There are a few ways to change/augment CC's system prompt.&lt;/p&gt;

&lt;h3&gt;
  
  
  Option 1: with output styles (recommended)
&lt;/h3&gt;

&lt;p&gt;Claude's output styles &lt;em&gt;are&lt;/em&gt; system prompts. If you want to completely override Claude's default personality, skillset, and behavior, this is how you can do it.&lt;/p&gt;

&lt;p&gt;This means you'll need a super high-quality, detail-oriented prompt. Claude Code can help you write one, but don't expect it to be as optimized as CC's default prompt. This is still a great exercise for prompt engineers, and also valuable for those who want to use a terminal-based agent for miscellaneous non-dev tasks.&lt;/p&gt;

&lt;p&gt;To recap: you'll do this by launching a Claude Code session and running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;/output-style:new [name] [verbose description]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Option 2: with append-system-prompt
&lt;/h3&gt;

&lt;p&gt;If you want to keep the general behavior of Claude Code's system prompt, but add a few more high-priority instructions, you can use the &lt;code&gt;--append-system-prompt&lt;/code&gt; flag. As part of the system prompt, CC will prioritize this over any other config settings (e.g. CLAUDE.md) or prompts.&lt;/p&gt;

&lt;p&gt;You can append your own instructions by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;claude --append-system-prompt "Never commit to main. Alert me when a new feature does not have unit tests written for it"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Option 3: with CLAUDE.md
&lt;/h3&gt;

&lt;p&gt;Your CLAUDE.md file is not a system prompt. Rather, it's a prioritized instruction that Claude Code will refer to &lt;em&gt;one tier below&lt;/em&gt; the instructions in the system prompt.&lt;/p&gt;

&lt;p&gt;Usually, A CLAUDE.md file is stored at the project level, and is automatically pulled into context when you launch a session. It'll typically store instructions and context relevant to a project, which will save you tokens and guarantee better outputs.&lt;/p&gt;

&lt;p&gt;You can run the &lt;code&gt;/init&lt;/code&gt; slash command to create it, or add one manually to your project's root directory.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep your dev skills sharp
&lt;/h2&gt;

&lt;p&gt;A hybrid of agentic and human dev can be a really refreshing balance for many programmers. You can keep learning good patterns, stay engaged during a dev session, and use your brain in a different way (vs. pure agentic dev). Thankfully, you've got plenty of ways to customize this to your liking with Claude Code's output styles. You can get a more fulfilling dev experience just by toggling system prompts.&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>learning</category>
    </item>
    <item>
      <title>Claude Code Subagents Quickstart: what they are + how to use them</title>
      <dc:creator>Shipyard DevRel</dc:creator>
      <pubDate>Thu, 25 Sep 2025 22:09:50 +0000</pubDate>
      <link>https://dev.to/shipyard/claude-code-subagents-quickstart-what-they-are-how-to-use-them-2jgc</link>
      <guid>https://dev.to/shipyard/claude-code-subagents-quickstart-what-they-are-how-to-use-them-2jgc</guid>
      <description>&lt;p&gt;Subagents are a popular capability of &lt;a href="https://docs.anthropic.com/en/docs/claude-code" rel="noopener noreferrer"&gt;Claude Code&lt;/a&gt;, which allow you to get specialized aid and advice during your dev sessions. Here's what they are, how to define them, and a few starter subagent personas. &lt;/p&gt;

&lt;h2&gt;
  
  
  What are subagents?
&lt;/h2&gt;

&lt;p&gt;Claude Code's &lt;a href="https://code.claude.com/docs/en/sub-agents" rel="noopener noreferrer"&gt;subagents&lt;/a&gt; are simply Claude instances with different areas of expertise. Instead of asking one generalist agent to do everything (e.g. classic Claude Code), you create specialists. &lt;/p&gt;

&lt;p&gt;Within a Claude Code session, you can invoke these subagents for tasks that might require more specialization, and thanks to their system prompts, you'll see better results. Subagents also benefit from having their own context windows, so they only ingest info relevant to their tasks. You'll save tokens, and see less of the "output degradation" that happens when the context window fills up during a long Claude session.&lt;/p&gt;

&lt;h2&gt;
  
  
  Subagents vs. multi-agent
&lt;/h2&gt;

&lt;p&gt;Subagents and &lt;a href="/blog/claude-code-multi-agent"&gt;multi-agent setups&lt;/a&gt; both involve multiple Claude instances. The biggest distinction here is the scope of the tasks that each type handles. A subagent gets spun up within a single Claude Code session to handle a specific task. It does its work in an isolated context window and returns a result to the parent session. A multi-agent setup (sometimes called an agent team) involves multiple CC sessions running in parallel or in sequence, often managed by an orchestrator.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to add subagents to Claude Code
&lt;/h2&gt;

&lt;p&gt;Claude Code makes it simple to write/customize/generate your own subagents.&lt;/p&gt;

&lt;p&gt;First, make sure you're on the latest version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can upgrade by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude update
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Start a CC session and run the &lt;code&gt;/agents&lt;/code&gt; slash command. From here, you'll be able to define a subagent at the project or user level. (We recommend starting out with project-level subagents, so you can customize them to use project-specific tools and domain knowledge).&lt;/p&gt;

&lt;p&gt;Claude will prompt you whether you want to create the subagent with Claude's help. This is a good move, since CC will use the context from your project to customize an agent to your needs. You'll write a summary of its responsibilities and Claude will fill out the rest. Agents are defined in natural language, but you'll want to use good prompt engineering practices to get the best results.&lt;/p&gt;

&lt;p&gt;Once you've finished the setup process, you can open up the resulting Markdown file and tweak it. For example, this is a snippet of the markdown config that Claude generated when asked to create a technical docs proofreader:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;proofreader&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Use&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;this&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;agent&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;when&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;you&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;need&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;to&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;proofread&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;and&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;correct&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;grammar&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;in&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;markdown&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;files,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;especially&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;technical&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;documentation&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;or&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;blog&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;posts.&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Examples:&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;lt;example&amp;gt;Context:&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;User&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;has&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;written&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;technical&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;blog&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;post&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;about&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;API&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;development&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;and&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;wants&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;it&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;reviewed&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;before&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;publishing.&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;user:&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;'I&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;just&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;finished&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;writing&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;blog&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;post&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;about&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;REST&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;APIs.&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Can&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;you&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;review&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;it&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;for&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;grammar&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;and&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;formatting?'&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;assistant:&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;'I'll&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;use&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;the&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;proofreader&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;agent&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;to&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;review&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;your&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;blog&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;post&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;for&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;grammar,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;formatting,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;and&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;technical&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;accuracy.'&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;lt;commentary&amp;gt;Since&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;the&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;wants&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;proofreading&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;of&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;technical&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;content,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;use&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;the&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;proofreader&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;agent&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;to&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;handle&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;grammar&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;correction&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;and&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;markdown&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;formatting&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;review.&amp;lt;/commentary&amp;gt;&amp;lt;/example&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;lt;example&amp;gt;Context:&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;User&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;has&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;updated&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;documentation&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;with&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;technical&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;that&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;needs&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;review.&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;user:&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;'I&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;updated&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;the&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;README&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;with&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;new&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;installation&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;instructions.&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Could&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;you&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;check&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;it&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;over?'&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;assistant:&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;'Let&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;me&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;use&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;the&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;proofreader&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;agent&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;to&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;review&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;your&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;README&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;for&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;clarity,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;grammar,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;and&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;proper&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;markdown&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;formatting.'&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;lt;commentary&amp;gt;The&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;wants&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;documentation&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;reviewed,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;so&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;use&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;the&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;proofreader&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;agent&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;to&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;ensure&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;proper&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;grammar&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;and&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;markdown&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;syntax.&amp;lt;/commentary&amp;gt;&amp;lt;/example&amp;gt;"&lt;/span&gt;
&lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sonnet&lt;/span&gt;
&lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;orange&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

You are an expert technical proofreader and grammar specialist with deep knowledge of software development terminology, markdown syntax, and technical writing conventions. You excel at maintaining clarity while preserving the author's intended casual tone and technical accuracy.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the Markdown frontmatter, you can customize the &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;description&lt;/code&gt;, choose your preferred Claude &lt;code&gt;model&lt;/code&gt;, and set the agent's UI &lt;code&gt;color&lt;/code&gt;. Optionally, you can grant it access to only select &lt;code&gt;tools&lt;/code&gt; (read, write, grep, etc) instead of all by default. &lt;/p&gt;

&lt;p&gt;In the content section, you'll be able to go into more detail on what the agent should know, and how it should respond to certain scenarios. Here you may want to list out workflows and define rules.&lt;/p&gt;

&lt;h2&gt;
  
  
  What subagents do I need?
&lt;/h2&gt;

&lt;p&gt;Think about what tasks you use Claude Code for. They probably can be boiled down into a few roles. Which agents you'll want really comes down to personal preference, but here are a few that we've found useful. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; You can paste these descriptions into CC during agent creation.&lt;/p&gt;

&lt;h3&gt;
  
  
  The System Architect
&lt;/h3&gt;

&lt;p&gt;This is a big-picture agent that advises you and nitpicks your design patterns. Use it to help you think through large features. It chimes in when you drift towards an anti-pattern.&lt;/p&gt;

&lt;p&gt;It's well-versed in the frameworks your app uses, and has plenty of expertise in systems at scale.&lt;/p&gt;

&lt;p&gt;This agent will be helpful when you ask it about optimizing logic, database choices, and why your monolith might need to become microservices.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Code Reviewer
&lt;/h3&gt;

&lt;p&gt;This is a very thorough agent that nitpicks every PR to find security holes, performance issues, unresolved comments, etc. This agent should be well-versed on optimal algorithms (e.g. critiquing your nested loops), but also understand that good code is elegant, not complicated.&lt;/p&gt;

&lt;p&gt;It has a sophisticated understanding of code syntax and style. This agent can act as one (of your many) checks and balances against LLM hallucinations. &lt;/p&gt;

&lt;h3&gt;
  
  
  The Debugger
&lt;/h3&gt;

&lt;p&gt;This debugging agent is methodical and patient. It traces your internal docs to run your code properly, and then ingests/analyzes logs to find the point of failure. It understands your services enough to recognize where a bug is coming from, and might recognize some common failure patterns.&lt;/p&gt;

&lt;p&gt;This agent works best alongside a dev, and asks questions to help it solve the problem (e.g. "when did this last work?", "what changed recently?"). &lt;/p&gt;

&lt;h3&gt;
  
  
  The DevOps Engineer
&lt;/h3&gt;

&lt;p&gt;This agent understands your deployment process + pipeline. It knows Docker, Kubernetes, and your CI/CD framework. It can help proofread your config files, and cross-reference with logs when you're not getting the expected behavior. You should be able to ask it how to optimize/implement best practices, and it should confidently answer from its glossary of DevOps patterns.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Playwright &lt;a href="/blog/playwright-agents-claude-code/"&gt;test agents&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Playwright maintains three custom subagents: &lt;a href="/blog/playwright-test-planner-agent/"&gt;the planner&lt;/a&gt;, &lt;a href="/blog/playwright-test-generator-agent/"&gt;the generator&lt;/a&gt;, and &lt;a href="/blog/playwright-test-healer-agent/"&gt;the healer&lt;/a&gt;. They can help with every stage of test writing, or even work together to create a strong automated test suite for your app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating smart personas
&lt;/h2&gt;

&lt;p&gt;What you need in a subagent will become more clear to you as you use Claude Code. Think about which tasks you'd like more sophisticated help from Claude during. Think about which parts matter less to you.&lt;/p&gt;

&lt;p&gt;Even though subagents are specialized and generally perform better for domain-specific tasks than stock Claude, they'll still have their blind spots and weaknesses. Engineers have reported strong results when including these weaknesses in their subagent system prompts. Also important to only throw each subagent the tasks that are in its wheelhouse.&lt;/p&gt;

&lt;p&gt;In your system prompt, it helps to instruct your agent to "be honest" or "be critical" or "be realistic". Many LLM system prompts default to an agreeable demeanor, so you'll want to be sure yours overrides this.&lt;/p&gt;

&lt;p&gt;You can also suggest that the subagent checks your reasoning with follow-up questions (e.g. "why do you want to make this change?", "how do you know this is the root of the problem?"). Making subagents a little argumentative and opinionated will protect you from bad design decisions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your subagent team
&lt;/h2&gt;

&lt;p&gt;In the beginning, you'll want to define and deploy your subagents one at a time. Get used to how they work, and how you can use them to get better results. You'll probably max out at about 3 or 4 subagents total; after that your own productivity may drop. &lt;/p&gt;

&lt;p&gt;You may rest on stock Claude Code for most of your general programming tasks, whereas your subagents will pick up anything more senior-level.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Using Claude Code? Give your agents ephemeral environments. They can deploy the code they write, pull logs, find + fix bugs, all with little-to-no human intervention. &lt;a href="https://shipyard.build/signup" rel="noopener noreferrer"&gt;Try it free for 30 days&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>automation</category>
    </item>
    <item>
      <title>How to prompt Gemini CLI to improve your Dockerfile</title>
      <dc:creator>Shipyard DevRel</dc:creator>
      <pubDate>Wed, 24 Sep 2025 20:54:43 +0000</pubDate>
      <link>https://dev.to/shipyard/how-to-prompt-gemini-cli-to-improve-your-dockerfile-2ofg</link>
      <guid>https://dev.to/shipyard/how-to-prompt-gemini-cli-to-improve-your-dockerfile-2ofg</guid>
      <description>&lt;p&gt;When you're generating a Dockerfile for your app, you might get something that &lt;em&gt;works&lt;/em&gt; but isn't optimized. This means it could be bloated with unnecessary packages (leading to potential vulnerabilities), not designed with dev/prod parity in mind, or not structured for faster builds.&lt;/p&gt;

&lt;p&gt;We found the optimal way to improve Dockerfiles with &lt;a href="https://ai.google.dev/gemini-api/docs/cli" rel="noopener noreferrer"&gt;Gemini CLI&lt;/a&gt;. Gemini CLI is great for this task, since it has such a large context window that it can take in a large chunk (if not all) of your codebase, and use that to help it write a working &lt;em&gt;and&lt;/em&gt; optimized Dockerfile.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why optimize your Dockerfile?
&lt;/h2&gt;

&lt;p&gt;It's quite simple to write an MVP, working Dockerfile for one of your services. Writing it the fast way will leave a few considerations off the table. More specifically, speed, size, and security.&lt;/p&gt;

&lt;p&gt;Since Dockerfiles are used for cloud-based dev and deployments, you'll want to keep them as small as you can. If you use a larger base image and add in a lot of extra tools, you'll hit your container registry and CI build minute limits much faster, and without any benefits at all. Keeping your images lean also means that there's a smaller attack surface (new vulnerabilities are found every single day, and fewer packages overall == less chance of a vulnerability).&lt;/p&gt;

&lt;p&gt;One of the best benefits of &lt;a href="https://docker.com" rel="noopener noreferrer"&gt;Docker&lt;/a&gt; is that it helps you make your software multi-environment friendly, so you can use the same (or similar) config from local dev to production. Having a &lt;a href="https://docs.docker.com/engine/reference/builder/" rel="noopener noreferrer"&gt;Dockerfile&lt;/a&gt; for every environment kind of defeats the purpose. Optimizing it means using env vars and keeping the overall architecture more abstract.&lt;/p&gt;

&lt;p&gt;Docker's multi-stage build pattern allows images to build faster by caching the topmost layers. For example, if you have lines 1-4 to manage imports and installs, and you swap around some instructions on lines 5 and 6, your Dockerfile will rebuild only from layer 5 down. You have to be strategic with where you perform certain instructions in the Dockerfile. Unoptimized Dockerfiles often don't take this into consideration, so your builds will be slower and thus more expensive.&lt;/p&gt;

&lt;p&gt;As with any software you're writing with a coding agent, you'll want to do several passes over your Dockerfile to iteratively improve it. &lt;/p&gt;

&lt;h3&gt;
  
  
  The hidden costs of "lazy" Dockerfiles
&lt;/h3&gt;

&lt;p&gt;Unoptimized Dockerfiles don't really have a huge impact locally, since you aren't paying for CPU, storage, or RAM expended. However, one of the major benefits of Dockerfiles is their versatility from local machine to cloud. And of course, when there's cloud, there are cloud costs. &lt;/p&gt;

&lt;p&gt;Cloud is typically billed usage-based. Slow-building + bloated Dockerfiles rack up your CI/CD usage faster, and consume your container registry bandwidth and storage. Inefficient resource usage also adds up in pre-production and production environments.&lt;/p&gt;

&lt;p&gt;A couple hundred extra MB might not make a huge difference outright, but when you think about how many times you're building/rebuilding/uploading per week, you're multiplying that spend quite a bit. &lt;/p&gt;

&lt;p&gt;Aside from literal "costs", slower, unoptimized Dockerfiles cost you when it comes to developer experience. Wait times add up, and rebuilding with updates will take longer than it needs to. Plus, they're harder/more tedious to debug. &lt;/p&gt;

&lt;h2&gt;
  
  
  Refining a Dockerfile through multiple prompts
&lt;/h2&gt;

&lt;p&gt;You'll get the best results if you optimize your Dockerfile in several different stages. This way, Gemini can be more thorough in every step, and you can review its suggestions in smaller, more palatable batches.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Analyzing the Dockerfile
&lt;/h3&gt;

&lt;p&gt;Before having it make any changes, you can kick off Gemini CLI's task with some context on what you want to accomplish. &lt;/p&gt;

&lt;p&gt;Here, you're basically priming it on how to understand your codebase. With its massive context window, it should have plenty of room to do so. &lt;/p&gt;

&lt;p&gt;During this stage, you should also be able to verify whether Gemini is on track. If it isn't, you can course-correct it and give it additional (paraphrased) context, or tell it to study certain files.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;"Please analyze my codebase and current Dockerfile and Docker Compose. What type of application is this, what are the main dependencies, and what optimization opportunities do you see? Here are my key files: [files]"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Review Gemini's output to make sure it understands both the task and info on the codebase it'll need to work with.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: The strategy
&lt;/h3&gt;

&lt;p&gt;Now that Gemini has some background in your config + codebase, you can start using it to map out a strategy. For example, when you say "optimize", what do you mean? Speed, security, image size, all of the above? Do you want to use a minimal image and strip down to only necessary dependencies?&lt;/p&gt;

&lt;p&gt;You'll also want to go into specs of your remote environment(s) (esp. since these might not be defined in your codebase). Are you using EC2, EKS, GKE? Kubernetes? Do you want to use the same Dockerfile across environments?&lt;/p&gt;

&lt;p&gt;If you have any more nonnegotiables about image specs, you can list them here. This may include compliance and dev workflow needs.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;"Based on your analysis, I want to prioritize [your priorities e.g. speed/size/security]. Follow the patterns [good practice] and [other good practice]. My deployment environment is [context]. I will need it to be compatible with [devtool] and have [xyz compliance]. Can you recommend the best optimization strategy and explain the trade-offs of different approaches?"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;By asking Gemini for alternatives, you're helping it reason through picking a solution, and force it to think about &lt;em&gt;not just the most common solution&lt;/em&gt;. Otherwise, it won't evaluate pros and cons of each. It may even select a different optimal solution via this approach; this helps it arrive at a more fleshed-out conclusion. (Plus you can and should have a say in which approach it takes).&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Implementation
&lt;/h3&gt;

&lt;p&gt;At this stage, you can ask Gemini CLI to revise your Dockerfile so that it is production-ready. You can help it stick to stricter logic by asking it to explain every decision it makes. &lt;/p&gt;

&lt;p&gt;You can also request that it generates a Markdown guide with start commands, test commands. Optionally, you might also want to wrap it in a Makefile. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;"Please revise and optimize this Dockerfile and Docker Compose following the strategy we discussed. Include detailed comments explaining each optimization, a .dockerignore file, and a markdown guide with specs + the commands I should use to build and test it."&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Refining the Dockerfile
&lt;/h3&gt;

&lt;p&gt;Now that you have an "improved" Dockerfile and &lt;a href="https://docs.docker.com/compose/" rel="noopener noreferrer"&gt;Docker Compose&lt;/a&gt;, you'll want to make sure they actually work. Ask Gemini CLI to run the Dockerfile and analyze the logs. You should also take a look at the performance yourself, to double-check what Gemini says. &lt;/p&gt;

&lt;p&gt;Let it know your impressions, and whether you want it to improve any aspects from here. &lt;/p&gt;

&lt;p&gt;You may tweak your Docker config via env vars: ask Gemini what their values &lt;em&gt;should&lt;/em&gt; be and test from there. Once its working locally, repeat in your PR, test, and staging environments.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to avoid
&lt;/h2&gt;

&lt;p&gt;As you've probably seen with LLMs, they can very much be "garbage in, garbage out" systems. You don't want to take shortcuts, and generic input will lead to generic output (not good for something as unique as your codebase). Here are a few particularly egregious things to avoid:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Don't skip the planning/discovery phase, this will help Gemini get the context it needs to give you customized results.&lt;/li&gt;
&lt;li&gt;Don't be vague. Saying "make it faster" won't get you solid results, because it casts too wide a net for an LLM to narrow down to the right answer.&lt;/li&gt;
&lt;li&gt;Don't skip testing, and don't trust an LLM to be correct when it attests that everything is working.&lt;/li&gt;
&lt;li&gt;Remember that the optimal solution for one codebase won't necessarily apply to yours. Take time to understand what you're working with. Above all, you should be the expert, not the LLM.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Better Dockerfiles for better deployments
&lt;/h2&gt;

&lt;p&gt;Using Gemini CLI's huge context window, you can give it enough context to optimize your Dockerfile to the best of its ability. We saw the best results with an iterative, multi-prompt approach, since that helped Gemini break each task into concrete steps, and us to steer it into the right direction along the way.&lt;/p&gt;

&lt;p&gt;Overall, better Dockerfiles lead to improvements all throughout the SDLC. You'll have better performance when running them locally, and cost savings in the cloud. They'll build faster and take advantage of Docker's layers/caching. You can apply these practices faster with Gemini's help.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>ai</category>
      <category>gemini</category>
    </item>
    <item>
      <title>Claude Code CLI Cheatsheet: config, commands, prompts, + best practices</title>
      <dc:creator>Shipyard DevRel</dc:creator>
      <pubDate>Fri, 22 Aug 2025 17:53:17 +0000</pubDate>
      <link>https://dev.to/shipyard/claude-code-cli-cheatsheet-config-commands-prompts-best-practices-13li</link>
      <guid>https://dev.to/shipyard/claude-code-cli-cheatsheet-config-commands-prompts-best-practices-13li</guid>
      <description>&lt;p&gt;&lt;strong&gt;Last updated:&lt;/strong&gt; 2025-08-18&lt;/p&gt;

&lt;p&gt;Claude Code is Anthropic's agentic coding tool that lives in your terminal and for now is SOTA for coding. This cheatsheet should give you everything you need to install, config, and use Claude Code for now...&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting started with Claude code
&lt;/h2&gt;

&lt;p&gt;Once you have a Claude Pro or Max subscription (or are paying for API access), you can start using Claude Code from your terminal. &lt;/p&gt;

&lt;p&gt;(Our advice: opt for the subscription if you're using it consistently and at a reasonable rate. It's worth getting API tokens if you don't want to deal with token refresh windows).&lt;/p&gt;

&lt;h3&gt;
  
  
  Installation
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Install globally:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @anthropic-ai/claude-code
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Prereqs:&lt;/strong&gt; Node.js 18 or newer&lt;/p&gt;

&lt;h3&gt;
  
  
  Auth
&lt;/h3&gt;

&lt;p&gt;Set up your Anthropic API key before launching CC.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Get your key:&lt;/strong&gt; Get an API key from the &lt;a href="https://console.anthropic.com/" rel="noopener noreferrer"&gt;Anthropic Console&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Set your key:&lt;/strong&gt; Set the &lt;code&gt;ANTHROPIC_API_KEY&lt;/code&gt; env var:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;ANTHROPIC_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"YOUR_ANTHROPIC_API_KEY"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alternatively, if you have a Pro or Max plan, you'll have the option to auth via your browser.&lt;/p&gt;

&lt;p&gt;Add this to your shell profile (e.g., &lt;code&gt;~/.bashrc&lt;/code&gt;, &lt;code&gt;~/.zshrc&lt;/code&gt;) to persist across sessions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Basic usage
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Interactive mode (REPL):&lt;/strong&gt; Start a conversational coding session.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;REPL with initial prompt:&lt;/strong&gt; Start with a specific question.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude &lt;span class="s2"&gt;"explain this project"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Print mode:&lt;/strong&gt; Query once and exit (great for scripting).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"explain this function"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Piping content:&lt;/strong&gt; Process piped input.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;logs.txt | claude &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"explain these errors"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Continue recent conversation:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude &lt;span class="nt"&gt;-c&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Resume specific session:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s2"&gt;"session-id"&lt;/span&gt; &lt;span class="s2"&gt;"continue working on this feature"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Config
&lt;/h2&gt;

&lt;p&gt;You're able to write (or generate) files to configure CC's basic behaviors. &lt;/p&gt;

&lt;h3&gt;
  
  
  Settings files
&lt;/h3&gt;

&lt;p&gt;Claude Code uses hierarchical settings stored in JSON files:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;User settings:&lt;/strong&gt; &lt;code&gt;~/.claude/settings.json&lt;/code&gt; (applies to all projects)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Project settings:&lt;/strong&gt; &lt;code&gt;.claude/settings.json&lt;/code&gt; (shared with team, checked into git)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Local project settings:&lt;/strong&gt; &lt;code&gt;.claude/settings.local.json&lt;/code&gt; (personal, ignored by git)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example settings.json:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"claude-sonnet-4-20250514"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"maxTokens"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4096&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"permissions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"allowedTools"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Read"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Write"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Bash(git *)"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"deny"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Read(./.env)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Read(./.env.*)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Write(./production.config.*)"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"hooks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"PostToolUse"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"matcher"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Write(*.py)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"hooks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"python -m black $file"&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Memory files (CLAUDE.md)
&lt;/h3&gt;

&lt;p&gt;Use &lt;code&gt;CLAUDE.md&lt;/code&gt; files to give context and instructions to Claude. They save time + tokens, and are super helpful for info you'd otherwise include in your prompts. These are loaded hierarchically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Global:&lt;/strong&gt; &lt;code&gt;~/.claude/CLAUDE.md&lt;/code&gt; (applies to all projects)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Project root:&lt;/strong&gt; &lt;code&gt;./CLAUDE.md&lt;/code&gt; (project-wide context)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Subdirectories:&lt;/strong&gt; Component-specific instructions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example CLAUDE.md:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Project context&lt;/span&gt;

&lt;span class="gu"&gt;## Coding standards&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Use TypeScript for all new code
&lt;span class="p"&gt;-&lt;/span&gt; Follow existing ESLint configuration
&lt;span class="p"&gt;-&lt;/span&gt; Write tests for all new functions using Jest
&lt;span class="p"&gt;-&lt;/span&gt; Use functional components with hooks in React

&lt;span class="gu"&gt;## Architecture&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Frontend: Next.js with TypeScript
&lt;span class="p"&gt;-&lt;/span&gt; Backend: Node.js with Express
&lt;span class="p"&gt;-&lt;/span&gt; Database: PostgreSQL with Prisma
&lt;span class="p"&gt;-&lt;/span&gt; State: Zustand for client state

&lt;span class="gu"&gt;## File organization&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Components in &lt;span class="sb"&gt;`src/components/`&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Utilities in &lt;span class="sb"&gt;`src/utils/`&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Tests alongside source files with &lt;span class="sb"&gt;`.test.ts`&lt;/span&gt; extension
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  CLI commands + flags
&lt;/h2&gt;

&lt;p&gt;You can use the following shell commands outside a Claude session.&lt;/p&gt;

&lt;h3&gt;
  
  
  Core commands
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;claude&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Start interactive REPL&lt;/td&gt;
&lt;td&gt;&lt;code&gt;claude&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;claude "query"&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Start REPL with initial prompt&lt;/td&gt;
&lt;td&gt;&lt;code&gt;claude "explain this project"&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;claude -p "query"&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Query via print mode, then exit&lt;/td&gt;
&lt;td&gt;&lt;code&gt;claude -p "review this code"&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;claude -c&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Continue most recent conversation&lt;/td&gt;
&lt;td&gt;&lt;code&gt;claude -c&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;claude -c -p "query"&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Continue in print mode&lt;/td&gt;
&lt;td&gt;&lt;code&gt;claude -c -p "run the tests"&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;claude -r "id" "query"&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Resume session by ID&lt;/td&gt;
&lt;td&gt;&lt;code&gt;claude -r "abc123" "finish the PR"&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;claude update&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Update to latest version&lt;/td&gt;
&lt;td&gt;&lt;code&gt;claude update&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;claude mcp&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Configure MCP servers&lt;/td&gt;
&lt;td&gt;&lt;code&gt;claude mcp add server-name&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  CLI flags
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Flag&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--add-dir&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Add additional working directories&lt;/td&gt;
&lt;td&gt;&lt;code&gt;claude --add-dir ../apps ../lib&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--allowedTools&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Allow specific tools without prompting&lt;/td&gt;
&lt;td&gt;&lt;code&gt;claude --allowedTools "Write" "Bash(git *)"&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--disallowedTools&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Block specific tools&lt;/td&gt;
&lt;td&gt;&lt;code&gt;claude --disallowedTools "Bash(rm *)"&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--model&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Use specific Claude model&lt;/td&gt;
&lt;td&gt;&lt;code&gt;claude --model claude-opus-4&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--max-turns&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Limit conversation turns&lt;/td&gt;
&lt;td&gt;&lt;code&gt;claude -p --max-turns 3 "query"&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--output-format&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Set output format (text/json/stream-json)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;claude -p --output-format json "query"&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--input-format&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Set input format&lt;/td&gt;
&lt;td&gt;&lt;code&gt;claude -p --input-format stream-json&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--verbose&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Enable verbose logging&lt;/td&gt;
&lt;td&gt;&lt;code&gt;claude --verbose&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--continue&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Continue most recent conversation&lt;/td&gt;
&lt;td&gt;&lt;code&gt;claude --continue&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--resume&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Resume specific session&lt;/td&gt;
&lt;td&gt;&lt;code&gt;claude --resume abc123&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--dangerously-skip-permissions&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Skip all permission prompts (proceed with caution)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;claude --dangerously-skip-permissions&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Interactive session commands
&lt;/h2&gt;

&lt;p&gt;You can use these slash commands &lt;em&gt;during&lt;/em&gt; a Claude Code session.&lt;/p&gt;

&lt;h3&gt;
  
  
  Built-in slash commands
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/help&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show all commands + custom slash commands&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/config&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Configure Claude Code settings interactively&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/allowed-tools&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Configure tool permissions interactively&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/hooks&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Configure hooks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/mcp&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Manage MCP servers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/agents&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Manage subagents (create, edit, list)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/vim&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Enable vim-style editing mode&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/terminal-setup&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Install terminal shortcuts (Shift+Enter for iTerm2/VS Code)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/install-github-app&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Set up GitHub Actions integration&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The &lt;code&gt;/help&lt;/code&gt; command shows all available slash commands, including your custom commands from &lt;code&gt;.claude/commands/&lt;/code&gt; and &lt;code&gt;~/.claude/commands/&lt;/code&gt; directories, as well as any commands you have from connected MCP servers.&lt;/p&gt;

&lt;h3&gt;
  
  
  File and directory references (@)
&lt;/h3&gt;

&lt;p&gt;You can reference files or directories in your prompts. (If you don't have an exact filename/location, CC can grep for it).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Single file:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; Review this component &lt;span class="k"&gt;for &lt;/span&gt;accessibility issues. @./src/components/Button.tsx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Directory (recursive):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; Add comprehensive error handling to all API routes. @./src/api/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Multiple files:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; Compare these two implementations. @./src/old.js @./src/new.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Glob patterns:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; Review all &lt;span class="nb"&gt;test &lt;/span&gt;files &lt;span class="k"&gt;for &lt;/span&gt;completeness. @./src/&lt;span class="k"&gt;**&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;.test.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Shell commands (!)
&lt;/h3&gt;

&lt;p&gt;You can run shell commands directly in a Claude session. Use the &lt;code&gt;!&lt;/code&gt; to bypass Claude's conversational mode, which will use more tokens to get the same result:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Single command:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;npm &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Shell mode toggle:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;
&lt;span class="c"&gt;# Now in shell mode. type ! again to exit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Advanced features
&lt;/h2&gt;

&lt;p&gt;We appreciate how customizable CC is, and it's quite easy to extend it with a few features like custom commands, hooks, MCP, and stored prompts.&lt;/p&gt;

&lt;h3&gt;
  
  
  Custom slash commands
&lt;/h3&gt;

&lt;p&gt;You can create your own CC slash commands. This is a good "shortcut" for pulling up a common prompt. Again, the more context the better (but also keep these abstract so they can be widely applied). Define them in Markdown files:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Project commands&lt;/strong&gt; (&lt;code&gt;.claude/commands/&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create a project-specific command&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; .claude/commands
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Analyze this code for performance issues and suggest optimizations:"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; .claude/commands/optimize.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Personal commands&lt;/strong&gt; (&lt;code&gt;~/.claude/commands/&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create a personal command for all projects&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; ~/.claude/commands
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Review this code for security vulnerabilities:"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; ~/.claude/commands/security.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Commands with arguments:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create parameterized command&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'Fix issue #$ARGUMENTS following our coding standards'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; .claude/commands/fix-issue.md

&lt;span class="c"&gt;# Use that command in a Claude session&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /fix-issue 123
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Advanced command with context:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;allowed-tools&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Bash(git add:*), Bash(git status:*), Bash(git commit:*)&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Create a git commit with context&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="gu"&gt;## Context&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Current status: !&lt;span class="sb"&gt;`git status`&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Current diff: !&lt;span class="sb"&gt;`git diff HEAD`&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Current branch: !&lt;span class="sb"&gt;`git branch --show-current`&lt;/span&gt;

Create a meaningful commit message based on the changes above.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Hooks for automation
&lt;/h3&gt;

&lt;p&gt;Hooks run shell commands automatically after specific prompts/events:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example: Auto-format Python files&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"hooks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"PostToolUse"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"matcher"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Write(*.py)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"hooks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
            &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"python -m black &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;$file&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Hook events:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;PreToolUse&lt;/code&gt;: Before tool execution (can block)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;PostToolUse&lt;/code&gt;: After tool execution&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;UserPromptSubmit&lt;/code&gt;: Before processing user input&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;SessionStart&lt;/code&gt;: At session startup&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Model Context Protocol (MCP)
&lt;/h3&gt;

&lt;p&gt;You can extend what Claude Code can do by adding MCP servers:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Add MCP server:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude mcp add my-server &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;123 &lt;span class="nt"&gt;--&lt;/span&gt; /path/to/server arg1 arg2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(Check your MCP tool's docs to get the right syntax here.)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Common MCP use cases:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Connect to Google Drive for design docs&lt;/li&gt;
&lt;li&gt;Integrate with Jira for ticket management
&lt;/li&gt;
&lt;li&gt;Add custom dev tooling&lt;/li&gt;
&lt;li&gt;Access external databases&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Conversation management
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Continue recent work:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude &lt;span class="nt"&gt;--continue&lt;/span&gt;
claude &lt;span class="nt"&gt;--continue&lt;/span&gt; &lt;span class="nt"&gt;--print&lt;/span&gt; &lt;span class="s2"&gt;"show me our progress"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Resume specific session:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude &lt;span class="nt"&gt;--resume&lt;/span&gt;  &lt;span class="c"&gt;# Shows picker&lt;/span&gt;
claude &lt;span class="nt"&gt;--resume&lt;/span&gt; session-id
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Save and restore context:&lt;/strong&gt;&lt;br&gt;
All CC conversations are auto-saved with full message history and tool state.&lt;/p&gt;
&lt;h2&gt;
  
  
  Common workflows
&lt;/h2&gt;

&lt;p&gt;Here are a few different tasks that CC can help with. Remember, the more context, the better, so if you can provide specifics around your ask, Claude will give better results (and you'll have fewer things to correct).&lt;/p&gt;
&lt;h3&gt;
  
  
  Code analysis
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; Analyze this codebase structure and suggest improvements. @./src/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Feature development
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; Implement a user auth system with JWT tokens and password hashing
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Bug fixing
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; Debug this error: "TypeError: Cannot read property 'id' of undefined" @./src/user-service.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Code review
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; Review this pull request for potential issues, performance problems, and adherence to our coding standards. @./src/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Testing
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; Generate comprehensive unit tests for this utility module. @./src/utils/validation.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Refactoring
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; Refactor this class to use dependency injection and make it more testable. @./src/services/EmailService.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

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


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; Generate API docs for all endpoints in this directory. @./src/routes/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  CI/CD integration
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# In GitHub Actions or other CI&lt;/span&gt;
claude &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"If there are any linting errors, fix them and suggest a commit message"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Security + permissions
&lt;/h2&gt;

&lt;p&gt;Claude Code defaults to asking permission for every single action it takes. If you trust it for a certain type of action (e.g. fetching links, reading files), you can grant it wider permissions. Most devs approve actions individually.&lt;/p&gt;
&lt;h3&gt;
  
  
  Permission system
&lt;/h3&gt;

&lt;p&gt;Claude Code lets you grant permissions as you see fit:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tool permissions:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Read&lt;/code&gt;: File reading operations&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Write&lt;/code&gt;: File writing/modification&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Bash&lt;/code&gt;: Shell command execution&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;MCP tools&lt;/code&gt;: External integrations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Configuration examples:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"permissions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"allowedTools"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Read"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Write(src/**)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Bash(git *)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Bash(npm *)"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"deny"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Read(.env*)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Write(production.config.*)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Bash(rm *)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Bash(sudo *)"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Best practices
&lt;/h3&gt;

&lt;p&gt;As with anything in dev, keep an eye on what permissions you're granting, and watch which shell commands are being run. Also: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ALWAYS review changes before accepting&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;.claude/settings.local.json&lt;/code&gt; for personal/sensitive settings&lt;/li&gt;
&lt;li&gt;Configure tool permissions for your env; verify everything (don't use YOLO mode unless you've put the proper safeguards in place)&lt;/li&gt;
&lt;li&gt;Use hooks for auto code formatting/validation&lt;/li&gt;
&lt;li&gt;Keep sensitive data in &lt;code&gt;.env&lt;/code&gt; files; deny CC permission to these&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Understanding Claude's session model
&lt;/h2&gt;

&lt;p&gt;If you want to best plan out your Claude sessions, you'll want to understand your constraints. Claude's tokens are granted by plan based on overall server load, so on busier days you'll get fewer. &lt;/p&gt;

&lt;p&gt;If you're not using the API for pay-as-you-go Claude access, you'll want to choose the Claude tier that works best for you. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pro:&lt;/strong&gt; for a medium-high coding workload. Expect to use continuously for smaller code changes, and as a supplement to your own coding. $20/month&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Max5:&lt;/strong&gt; for an intense coding workload. 5x the token allowance of Pro. Opus access. $100/month&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Max20:&lt;/strong&gt; for near-autonomous, nonstop, heavy development workloads with multiple sessions/agents. Significantly larger context window. 20x the token allowance of Pro. Opus access. $200/month&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sessions kick off as soon as you send your first message, and last five hours. If you're using Opus, you'll burn through tokens much faster.&lt;/p&gt;

&lt;p&gt;It's most token-efficient (and guarantees better outputs) if you start different sessions for different tasks.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Extra resources&lt;/strong&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Claude has built-in access to its own docs: you can ask questions about features directly&lt;/li&gt;
&lt;li&gt;Check out the &lt;a href="https://docs.anthropic.com/en/docs/claude-code" rel="noopener noreferrer"&gt;official docs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;/help&lt;/code&gt; in your Claude session&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Need to take CC to the next level? Give your AI agents ephemeral environments where they can deploy code, pull logs, and fix bugs autonomously. &lt;a href="https://shipyard.build/signup" rel="noopener noreferrer"&gt;Try Shipyard free for 30 days&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>tutorial</category>
      <category>productivity</category>
    </item>
    <item>
      <title>The Docker Compose Test Environment Guide</title>
      <dc:creator>Shipyard DevRel</dc:creator>
      <pubDate>Wed, 04 Jun 2025 15:54:50 +0000</pubDate>
      <link>https://dev.to/shipyard/the-docker-compose-test-environment-guide-19lb</link>
      <guid>https://dev.to/shipyard/the-docker-compose-test-environment-guide-19lb</guid>
      <description>&lt;p&gt;&lt;a href="https://docs.docker.com/compose" rel="noopener noreferrer"&gt;Docker Compose&lt;/a&gt; is an invaluable development tool for microservices apps. If you’re working with containers, you’ll likely use it in some capacity. Whether you’re using it for orchestration or app definition (or both), Compose abstracts away the complexity and guesswork involved in container management.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a Docker Compose environment?
&lt;/h2&gt;

&lt;p&gt;Docker Compose has built-in container orchestration for single and multi-service environments. It’s the obvious choice for setting up a local dev environment for containerized workloads: you can use it to run your Dockerized app with limited config or overhead. For example, you might use Compose to spin up the containers, see how they interact with each other, and do some simple testing. &lt;/p&gt;

&lt;h2&gt;
  
  
  Docker Compose for the perfect local environment
&lt;/h2&gt;

&lt;p&gt;A Docker Compose environment might be more limited and less complex from what you’d use when you have cloud resources available. However, sometimes Compose’s orchestration is all you need. Compose is especially convenient during the inner dev loop, since you can spin up environments within minutes, and run them without overwhelming your laptop.&lt;/p&gt;

&lt;p&gt;For these reasons, teams find Compose sits at a good balance between simplicity and capability. They can use it to provide build instructions/config for in-progress services, and pull prebuilt images from a container registry. &lt;/p&gt;

&lt;p&gt;Docker Compose also takes care of basic networking between containers, and allows users to configure external networks. With Compose, you can also create custom links (aliases) between containers.&lt;/p&gt;

&lt;p&gt;Compose excels because it has top-notch DevEx. By virtue of being so straightforward, you can spend more time developing your app instead of tweaking orchestration config. The Docker CLI has thorough logging, so fixing/improving your Compose definition isn’t a huge task.&lt;/p&gt;

&lt;h2&gt;
  
  
  Should I use Docker Compose for cloud environments?
&lt;/h2&gt;

&lt;p&gt;When you have cloud compute at your disposal, you may want to take advantage of that. Compose is exceptional because it is so lightweight, but with the tradeoff of limited scalability. You can get more efficient (and better optimized) orchestration with a lightweight Kubernetes distro instead, which will also be closer in parity to your production environment. &lt;/p&gt;

&lt;p&gt;At the end of the day, Compose is the clear winner for local dev, but its benefits are lost by the time you get to remote environments. Instead, you might use your Compose file as an application definition (instead of a Kubernetes manifest) for your ephemeral, staging, and production environments. We’ll get into that shortly.&lt;/p&gt;

&lt;h2&gt;
  
  
  K3s: lightweight, yet capable container orchestration
&lt;/h2&gt;

&lt;p&gt;Rancher’s &lt;a href="https://k3s.io" rel="noopener noreferrer"&gt;k3s&lt;/a&gt; distribution (named after the abbreviation of “Kubernetes” at half-length) is a lightweight alternative. Unlike stock k8s, k3s is much easier to configure and tweak. While it has fewer features, it still is pretty powerful and can be a good approximation of production orchestration, especially for intermediate-stage environments.&lt;/p&gt;

&lt;p&gt;Sometimes, it makes sense to use k3s at the local level, but its value really shines in cloud dev environments, staging, and ephemeral environments. With a much smaller memory footprint, it’s a stellar alternative for most use cases that don’t require massive scaling, complex networks, or multi-tenant architecture. &lt;/p&gt;

&lt;h2&gt;
  
  
  Docker Compose to Kubernetes for preview environments
&lt;/h2&gt;

&lt;p&gt;If you want to forego Kubernetes manifests altogether, you’ll save yourself the hassle of defining, tweaking, and optimizing orchestrations. Instead, you might have a &lt;code&gt;compose.dev.yml&lt;/code&gt; and a &lt;code&gt;compose.staging.yml&lt;/code&gt; and/or &lt;code&gt;compose.prod.yml&lt;/code&gt;. These will be more or less similar, with varying services (perhaps debug containers instead of final-built images). This way, when something works in one environment but not another, you can narrow down the issue to the places where the config differs (or conclude that its infrastructure-related).&lt;/p&gt;

&lt;p&gt;With a platform like Shipyard, you can get all the perks and convenience of using Docker Compose for local dev. Once you’re done iterating, Shipyard transpiles your Compose file to Kubernetes manifests, so you get production-grade orchestration for every branch-based ephemeral environment. After you merge your code changes, you can take that same (or similar) Compose file and use it for a service like AWS Elastic Beanstalk for your production deployment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Elastic Beanstalk for Compose in production
&lt;/h2&gt;

&lt;p&gt;One major benefit of Compose is that if you set up your environment workflow right, you can use Compose as your application definition throughout different environments. This prevents configuration drift and helps keep all your service definitions constant. After all, it’s much simpler to handle a couple of Compose files instead of writing custom Kubernetes manifests for every type of environment in your SDLC.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/Welcome.html" rel="noopener noreferrer"&gt;AWS Elastic Beanstalk&lt;/a&gt; ingests your app and Compose file, and uses that to orchestrate your application for staging or production deployments. It’s typically lauded for its ease-of-use, especially since it can harness EC2 with relatively little setup. &lt;/p&gt;

&lt;p&gt;If you wanted a purely-Compose environment workflow, you could use Docker Compose’s native orchestration locally, Shipyard’s ephemeral environments for test/QA and/or staging, and Elastic Beanstalk for staging and/or prod.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tying it all together
&lt;/h2&gt;

&lt;p&gt;Docker Compose plays an important role in environment workflows from development to deployment. Using Compose can remove some of the lift with regards to config and orchestration, and abstract away the trickier parts of multi-container management. &lt;/p&gt;

&lt;p&gt;Many teams who use Shipyard love Compose for its flexibility. They use it for local development, and then pass their Compose file to Shipyard to gain production-level orchestration for every PR/MR. Once they’re done iterating and testing, some use Compose as the application definition for a service like Elastic Beanstalk. If you’re looking for dev/prod parity without the hassle, &lt;a href="https://shipyard.build/signup" rel="noopener noreferrer"&gt;sign up for a 30-day free trial&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>devops</category>
      <category>testing</category>
    </item>
    <item>
      <title>Local-first CI/CD with Makefiles</title>
      <dc:creator>Shipyard DevRel</dc:creator>
      <pubDate>Thu, 01 May 2025 15:42:37 +0000</pubDate>
      <link>https://dev.to/shipyard/local-first-cicd-with-makefiles-4g8o</link>
      <guid>https://dev.to/shipyard/local-first-cicd-with-makefiles-4g8o</guid>
      <description>&lt;p&gt;Continuous integration often only happens after a commit or a PR, in a remote environment. However, there’s a ton of benefit from designing these pipelines at the local level, and running them early on. This way, you’re using the same steps throughout the SDLC, but running them across different environments, which helps show incompatibilities between your application and any new code changes. Here’s why you should keep your pipeline logic in Makefiles and use them from development to deployment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why local-first makes sense for CI/CD
&lt;/h2&gt;

&lt;p&gt;Continuous integration isn’t something that needs to be restricted to remote pipelines. You can get a lot more mileage out of your CI/CD pipelines if you begin integration locally. If you’re able to resolve bugs uncovered by your pipeline right then and there on your machine, you’ll save a lot of time (and CI runner costs).&lt;/p&gt;

&lt;p&gt;The core philosophy of continuous integration is keeping code changes small and modular. That way, you can test each new one individually and thoroughly, and stay pretty aware how it affects your codebase. CI also emphasizes moving fast to avoid merge conflicts or a stale trunk. &lt;/p&gt;

&lt;p&gt;The best way to do this is to find out how your code changes fare early on: at the local level. That way, you’re keeping your commit history cleaner, and only pushing changes that pass local integration steps. This way, you can stay in the inner loop, take more risks, and trust your code changes more, instead of feeling uncertain until they hit a remote branch and trigger your cloud-hosted CI/CD.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keeping your logic outside of the pipelines
&lt;/h2&gt;

&lt;p&gt;You don’t want to spend time building out your CI/CD logic within the pipeline itself. Someday, you might change CI/CD platform providers, and it can take months to transpose one YAML spec to a different YAML spec.&lt;/p&gt;

&lt;p&gt;The best practice for writing pipelines is treating them as simply a wrapper for your build/test/deploy steps. This way, you can have a single source of truth for both your local and remote workflows, instead of having fully separate pipelines for every stage. This makes maintaining CI/CD much more straightforward, and helps guide you towards good pipeline design principles.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Makefiles?
&lt;/h2&gt;

&lt;p&gt;The Makefile spec has been around since 1976, and is still considered one of the best methods to define build workflows.&lt;/p&gt;

&lt;p&gt;A Makefile serves as a collection of scripts linked to &lt;code&gt;make&lt;/code&gt; aliases. For example, if you want to start your app’s PostgreSQL database, you’d run &lt;code&gt;make postgres.start&lt;/code&gt;, and in your Makefile, you’ve defined that alias like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;postgres.start&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    docker compose up &lt;span class="nt"&gt;-d&lt;/span&gt; postgres
    docker compose &lt;span class="nb"&gt;exec &lt;/span&gt;postgres &lt;span class="se"&gt;\&lt;/span&gt;
      sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s1"&gt;'while ! nc -z postgres 5432; do sleep 0.1; done'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Makefiles make it easy to ensure your build steps stay consistent. Instead of memorizing (or copy-pasting) several steps, you can invoke the same steps in the same order, every time. &lt;/p&gt;

&lt;p&gt;And these steps will likely not change too much throughout your SDLC. The main difference will be the infrastructure they’re run against (e.g. a small local dev environment vs. a staging environment that approximates all production services). &lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you want to learn more about the beauty of Makefiles, check out our post &lt;a href="https://shipyard.build/blog/makefiles-for-modern-development/" rel="noopener noreferrer"&gt;"Makefiles for Modern Development”&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Using your remote pipeline as a wrapper for your Makefile
&lt;/h2&gt;

&lt;p&gt;A Makefile brings all your tooling together into a centralized spec. You’re invoking different commands and using different tools, so it really is a wrapper in itself. This means that you’ll want your Makefile to be polished and up-to-date, since it should act as your single-source-of-truth for dev/test workflows.&lt;/p&gt;

&lt;p&gt;Once you have that ready to go, your CI/CD YAML should be really straightforward to write. Essentially, it’ll serve as a wrapper for your Makefile. In this example, we’re using &lt;code&gt;make&lt;/code&gt; commands in a GitHub Actions workflow, where each step invokes a command from the Makefile. This keeps it consistent: you know &lt;em&gt;exactly&lt;/em&gt; what is happening in each step, because this is a similar workflow to the one you’ve used during prior development checkpoints (e.g. locally). You can solve for dev/prod parity issues by seeing where the pipeline fails (you already know these exact steps have succeeded on your machine, so it’ll be easier to narrow down the point of failure).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;dev&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;ci&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout repository&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install dependencies&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;make deps&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Lint code&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;make lint&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run tests&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;make test&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build app&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;make build&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build Docker image&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;make docker.build&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Push Docker image&lt;/span&gt;
        &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;github.ref == 'refs/heads/main' &amp;amp;&amp;amp; github.event_name == 'push'&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;make docker.push&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Using a Makefile as your local CI/CD pipeline
&lt;/h2&gt;

&lt;p&gt;Once your CI/CD logic is already living in your Makefile, using anything &lt;em&gt;but&lt;/em&gt; a Makefile is overkill for &lt;strong&gt;most&lt;/strong&gt; local CI/CD workflows. Why add yet another wrapper? Your Makefile can invoke and stack &lt;code&gt;make&lt;/code&gt; targets, so you can bundle a few together to run your CI/CD steps in order. You can also define a few different variants (e.g. defining one workflow that seeds the database and runs tests, and another that just lints and builds).&lt;/p&gt;

&lt;p&gt;In your Makefile, you can group your existing targets together:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;all&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;deps lint test build&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then you simply run a single &lt;code&gt;make&lt;/code&gt; command to execute the entire local CI/CD process:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;make all
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Better pipelines == better production
&lt;/h2&gt;

&lt;p&gt;When you’ve finetuned your CI/CD pipeline, you’ll start getting more value from it by using it at every major SDLC stage. As your code changes go through different “gates” and environments, your CI/CD can stress test and ensure that they’re production-ready. &lt;/p&gt;

&lt;p&gt;And if you want to run CI/CD against full-stack, production-like environments on every code change, Shipyard has you covered. It manages the lifecycle of ephemeral environments through GitOps, so they spin up when you open a PR, update when you make a commit, and spin down automatically on a merge or timeout. It’s that easy. This way, you can run your full E2E test suite whenever you need to, and do CI/CD the right way. &lt;a href="https://shipyard.build/signup" rel="noopener noreferrer"&gt;Try it free for 30 days&lt;/a&gt;, or &lt;a href="https://shipyard.build/contact" rel="noopener noreferrer"&gt;jump on a call&lt;/a&gt; and we’ll help you get set up.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>testing</category>
      <category>tooling</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Test Your Vibe Coding with Ephemeral Environments</title>
      <dc:creator>Shipyard DevRel</dc:creator>
      <pubDate>Tue, 22 Apr 2025 19:44:39 +0000</pubDate>
      <link>https://dev.to/shipyard/test-your-vibe-coding-with-ephemeral-environments-3lah</link>
      <guid>https://dev.to/shipyard/test-your-vibe-coding-with-ephemeral-environments-3lah</guid>
      <description>&lt;p&gt;Vibe coding is taking the tech world by storm. Why? It’s a lightning-fast way to prototype the app of your dreams. Just come up with an idea, tell your favorite LLM, and keep iterating/tweaking it until it does everything you want it to. Sounds too good to be true, right?&lt;/p&gt;

&lt;p&gt;Well, yes and no. Without proper testing, your vibe-coded proof-of-concept might be a little brittle or prone to bugs. However, it’s very possible to use good engineering practices to ensure your app runs smoothly and as expected. Here’s how you can stay ahead of some common LLM missteps.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where vibe coding falls short
&lt;/h2&gt;

&lt;p&gt;When you ask ChatGPT or Claude a question, how often is it actually correct? Not quite often enough for you to take its output as 100% factual. LLMs have a major weak spot: accuracy. An LLM will answer your prompt by responding with the most frequent associations/patterns it sees in its training data.&lt;/p&gt;

&lt;p&gt;That’s where vibe coding becomes a liability. There’s a lot of poorly-written, vulnerable code in the world, and therefore in LLM training data. The output of your vibe coding copilot could be derived from a StackOverflow comment with two upvotes, or it could be an actual best-practice solution. &lt;/p&gt;

&lt;p&gt;And this only gets worse the more niche your vibe coding project gets… &lt;/p&gt;

&lt;p&gt;LLMs don’t always understand the context of your application, and will thus not “understand” the intended behavior. Being &lt;em&gt;as specific as possible&lt;/em&gt; will only help you (e.g. “build me a personal finance app” vs. “build me a React, Django, Postgres app where I can track my saving and spending, and enter purchases into a form with three fields”).&lt;/p&gt;

&lt;p&gt;In short, vibe coding is a great way to get rapid-fast prototypes, at the expense of cohesive, secure software design. This means you’ll want to test it accordingly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Don’t “vibe test” your vibe coding
&lt;/h2&gt;

&lt;p&gt;Rule #1 when it comes to vibe coding: write your own tests. (Or at least pair program them with your coding copilot).&lt;/p&gt;

&lt;p&gt;Yes, this will probably take a lot longer than building your app itself. But if you’re working on an app you care about, or something business-critical, you’ll want to minimize any risks already inherent to vibe coding.&lt;/p&gt;

&lt;p&gt;You, as a person, understand in your mind &lt;em&gt;exactly&lt;/em&gt; what you want your app to do (down to subtle little things that you can’t quite articulate to your LLM buddy). &lt;/p&gt;

&lt;p&gt;Take some time to think about what functionalities need extra verification, and brainstorm any edge and corner cases. Writing end-to-end tests that simulate real-world workflows can be especially helpful, since a vibe coded application might have some components that don’t mesh super well, especially if they were tacked on later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ephemeral environments for vibe coding
&lt;/h2&gt;

&lt;p&gt;When you’re deploying your vibe-coded app to production, you’ll want to see how it runs on real infrastructure. One of the most frustrating issues with vibe coding is configuration. Since you’re working with LLMs, many of the packages that get pulled into your app aren’t versioned correctly, configured the right way, or are very out-of-date (especially dependent on that LLM’s training data).&lt;/p&gt;

&lt;p&gt;Instead of taking a “push and pray” approach to production, you can individually test features, PRs, branches, and even main before you deploy. After creating and testing a few vibe-coded apps, we found out there was a bit of a disconnect between the vibe coding environment (which these apps are optimized to run on) and any other environment (staging, preview, or production). With ephemeral environments, you can sort out these issues and approximate how your app will run in production.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Vibe coding
&lt;/h3&gt;

&lt;p&gt;This is the fun part. Vibe coding needs no intro, just go to your online LLM-enabled IDE, type in your prompt, and watch it piece together a full-stack app step-by-step. If you want to make this app extra portable, and make it easier to build/deploy/run anywhere, make sure to ask the LLM to include Docker Compose orchestration (this works best when you ask in your initial prompt).&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%2Fhthlien2aqksikogmu27.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%2Fhthlien2aqksikogmu27.png" alt="Vibe coding an application" width="800" height="446"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We evaluated a few different online vibe coding IDEs, and were impressed by all, although &lt;a href="https://lovable.dev" rel="noopener noreferrer"&gt;Lovable.dev&lt;/a&gt; was the clear standout. We were able to get a few solid apps built on the free tier, and we appreciated that credits refresh on a daily basis. Also, Lovable was helpful for making corrections and debugging, without breaking the entire app.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Exporting your app to GitHub
&lt;/h3&gt;

&lt;p&gt;Once you’re feeling solid about your app, export it to a GitHub repository. Many vibe coding apps will allow you to sync code changes to the repository, and the agent can sometimes even commit to the repo when you prompt it to. Good source control can help you revert code changes that break things, which isn’t unusual when an LLM enters the equation.&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%2Fqmspomn704pip7ld4p1f.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%2Fqmspomn704pip7ld4p1f.png" alt="Export Lovable to GitHub" width="800" height="469"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Updating your config
&lt;/h3&gt;

&lt;p&gt;In this example, we’ll be using &lt;a href="https://shipyard.build" rel="noopener noreferrer"&gt;Shipyard&lt;/a&gt; as our &lt;a href="https://shipyard.build/ephemeral-environments" rel="noopener noreferrer"&gt;ephemeral environment&lt;/a&gt; management platform. If you’re new to Shipyard, you can &lt;a href="https://shipyard.build/signup" rel="noopener noreferrer"&gt;sign in with GitHub or GitLab to kick off a 30-day free trial&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Shipyard takes a Docker Compose application definition, and uses that to generate Kubernetes manifests for your app’s orchestration. In your app’s Compose file, find the frontend-facing service. Add a label to set this as the primary route:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;frontend&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
      &lt;span class="na"&gt;dockerfile&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Dockerfile&lt;/span&gt;
    &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;shipyard.route&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/'&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;8080:8080"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Config will vary between apps, and any app generated from an LLM is always a wildcard in terms of stack, tools, and setup. &lt;a href="https://docs.shipyard.build/docs/docker-compose" rel="noopener noreferrer"&gt;Check out the Shipyard Docker Compose docs&lt;/a&gt; if your app requires additional labels.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Running the app in an ephemeral environment
&lt;/h3&gt;

&lt;p&gt;Once you’ve configured your Docker Compose file, you’re all set to get it running in an ephemeral environment. From your Shipyard dashboard, you can create a new application and select your repo. &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%2F4bv0nvd7etpnsuw0nxqp.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%2F4bv0nvd7etpnsuw0nxqp.png" alt="Build your app in an ephemeral environment" width="800" height="545"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From here, your app will build. You can check out the &lt;strong&gt;Build&lt;/strong&gt;, &lt;strong&gt;Run&lt;/strong&gt;, and &lt;strong&gt;Deploy&lt;/strong&gt; &lt;a href="https://docs.shipyard.build/docs/build-details#live-build--run-logs" rel="noopener noreferrer"&gt;logs&lt;/a&gt; to see if you need to adjust anything config-wise. To make changes, go back to your vibe coding IDE and either manually edit the code, or ask the LLM to solve for the issues the logs are showing. As soon as you (or the agent) commit that, the Shipyard environment will rebuild to reflect those code changes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5: Testing, UATing, and previewing your app
&lt;/h3&gt;

&lt;p&gt;Now, you can visit your app and interact with it on near-production infrastructure. Test all possible workflows manually, and/or &lt;a href="https://docs.shipyard.build/docs/authentication#all-applications" rel="noopener noreferrer"&gt;add your teammates&lt;/a&gt; to help with review. &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%2Fl481tloukxbiu5sgu25z.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%2Fl481tloukxbiu5sgu25z.png" alt="Previewing a vibe coded app" width="800" height="564"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can even vibe code (or manually write) a CI/CD pipeline to run your automated tests against this app. Doing this on every new code change will make it easier to keep iterating until your app is up to spec.&lt;/p&gt;

&lt;p&gt;And most importantly, you can now rest easy knowing that your app doesn’t come with any surprises!&lt;/p&gt;

&lt;h2&gt;
  
  
  Shipyard + vibe coding = trusty releases
&lt;/h2&gt;

&lt;p&gt;We get it, you love the convenience of vibe coding, but you don’t love its unpredictability. That’s where a platform like Shipyard can help. Funnel your vibe-coded app through a few gates of ephemeral environments, get several sets of eyes on it, run tests against it, and then release it with confidence. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://shipyard.build/signup" rel="noopener noreferrer"&gt;Try it free for 30 days&lt;/a&gt;, or &lt;a href="https://shipyard.build/contact" rel="noopener noreferrer"&gt;book a call&lt;/a&gt; to learn how it all works.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>programming</category>
    </item>
    <item>
      <title>How to Measure DORA Change Fail Rate</title>
      <dc:creator>Shipyard DevRel</dc:creator>
      <pubDate>Thu, 10 Apr 2025 14:43:51 +0000</pubDate>
      <link>https://dev.to/shipyard/how-to-measure-dora-change-fail-rate-1cm5</link>
      <guid>https://dev.to/shipyard/how-to-measure-dora-change-fail-rate-1cm5</guid>
      <description>&lt;p&gt;As with all four key DORA metrics, &lt;strong&gt;measurement&lt;/strong&gt; is the first step to &lt;strong&gt;improvement&lt;/strong&gt;. Change fail rate is critical to track because it demonstrates your team’s success at delivering reliable, stable code. Having strong scores when it comes to &lt;a href="https://shipyard.build/blog/measure-dora-deployment-frequency/" rel="noopener noreferrer"&gt;deployment frequency&lt;/a&gt; and &lt;a href="https://shipyard.build/blog/measure-dora-change-lead-time/" rel="noopener noreferrer"&gt;lead time for changes&lt;/a&gt; is only impressive &lt;strong&gt;&lt;em&gt;if&lt;/em&gt;&lt;/strong&gt; you have a comparatively low change failure rate. Here’s how you can assess how stable your application is.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is change fail rate (CFR)?
&lt;/h2&gt;

&lt;p&gt;Change fail rate (CFR) is one of the four &lt;a href="https://dora.dev" rel="noopener noreferrer"&gt;DORA&lt;/a&gt; key metrics. It represents how often a change (or deployment) to production doesn’t perform as expected, or introduces a bug/regression.&lt;/p&gt;

&lt;p&gt;DORA measures software throughput and stability, which are arguably the most critical dimensions when it comes to evaluating your team’s performance. Change fail rate (as of 2024) is considered the primary &lt;strong&gt;stability&lt;/strong&gt; metric, among the four keys. This means that CFR is equally important to track as the velocity metrics, and will demonstrate if your fast deployment rates are at the expense of often-faulty code.&lt;/p&gt;

&lt;p&gt;Any time you push a patch or hotfix, the code change you’re resolving is counted as a “failed deployment”. Sometimes these don’t surface until much later, when you find a bug that had been laying low for months or years.This is all important to keep track of, because it reveals faulty testing or QA practices, which may be either process or pipeline-based. &lt;/p&gt;

&lt;h2&gt;
  
  
  How to measure change fail rate
&lt;/h2&gt;

&lt;p&gt;Change fail rate is represented as a percentage: it is the percentage of faulty deployments from your number of total deployments.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Change fail rate = ((number of failed deployments) / (number of total deployments)) * 100&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;It’s a simple formula, but the challenging part comes from collecting enough deployment data to measure trends. If you haven’t already, it’s helpful to find a way to automate this data collection, preferably into a spreadsheet. From there, you can track change fail rate over the time intervals of your choosing, and compare those rates to your other DORA metrics. &lt;/p&gt;

&lt;h3&gt;
  
  
  Measuring CFR through story status
&lt;/h3&gt;

&lt;p&gt;One straightforward way to get change fail rate is by crunching story data. Keep count of every ticket that results in a deployment, as well as every ticket that goes from &lt;code&gt;Completed&lt;/code&gt; back to &lt;code&gt;In progress&lt;/code&gt;. With most ticket systems, this can be a good way to approximate how often your completed tickets need a rework. However, keep in mind that it’s only as accurate as your ticket tracking — if you aren’t documenting thoroughly, you won’t get a reliable estimate on your change fail rate.&lt;/p&gt;

&lt;h3&gt;
  
  
  Measuring CFR through GitHub
&lt;/h3&gt;

&lt;p&gt;If you’re using GitHub’s Deployment feature for production releases, you can use &lt;a href="https://docs.github.com/en/rest/deployments/deployments?apiVersion=2022-11-28" rel="noopener noreferrer"&gt;GitHub’s REST API to collect deployment events&lt;/a&gt;. At minimum, you’ll want to record timestamps for when each deployment was created and/or modified, and grab deployment statuses (&lt;code&gt;success&lt;/code&gt;, &lt;code&gt;failure&lt;/code&gt;, &lt;code&gt;error&lt;/code&gt;).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;GET /repos/my-username/my-project/deployments
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Measuring CFR through GitLab
&lt;/h3&gt;

&lt;p&gt;GitLab’s designated &lt;a href="https://docs.gitlab.com/ee/api/deployments.html" rel="noopener noreferrer"&gt;Deployment API&lt;/a&gt; can give you the data you need to calculate change fail rate. A simple call returns all deployments for a given project, and you can also grab the timestamp and its status. From there, you can compare the number of deployments with &lt;code&gt;failed&lt;/code&gt; status to the overall number.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;GET /projects/:id/deployments
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For Ultimate subscribers, GitLab offers a &lt;a href="https://docs.gitlab.com/ee/api/dora/metrics.html" rel="noopener noreferrer"&gt;DORA metrics API&lt;/a&gt;, where you can directly request DORA change fail rate.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;GET /projects/:id/dora/metrics
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What is a good change fail rate?
&lt;/h2&gt;

&lt;p&gt;As of the &lt;a href="https://dora.dev/research/2024/" rel="noopener noreferrer"&gt;2024 DORA report&lt;/a&gt;, the highest-performing teams (those who have attained the “elite” performance standard) have a change fail rate of 5%. About one-fifth of teams surveyed fall within this range.&lt;/p&gt;

&lt;p&gt;Interestingly, teams within DORA’s “high” performance standard tend to have a worse change fail rate than those within the “medium” standard. Teams with a &lt;strong&gt;lead time of under a week&lt;/strong&gt; tend to see a &lt;strong&gt;change fail rate of 20%&lt;/strong&gt;, while those with a &lt;strong&gt;lead time between one week and one month&lt;/strong&gt; see a &lt;strong&gt;change fail rate of 10%&lt;/strong&gt;. Often, teams struggle to maintain a low change fail rate when they’re pushing code fast (can be from lack of QA automation, code review, test coverage, etc.).&lt;/p&gt;

&lt;p&gt;There doesn’t have to be a tradeoff between throughput and stability. With thorough pipelines and processes in place, your team should be able to deliver features fast, and &lt;em&gt;trust&lt;/em&gt; the features they’re delivering. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TLDR:&lt;/strong&gt; change fail rate should be taken with the context of throughput. If you have a high throughput and low change fail rate, you’re doing well. Remember, DORA metrics are best used to measure your &lt;em&gt;improvement&lt;/em&gt;. As long as your change fail rate is going down (and not at the expense of your deployment velocity or lead time), this is a good indicator of performance. You don’t need to aim for “elite” numbers, as your team’s ideal change fail rate might look different from that of another org.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trying to reduce change fail rate?
&lt;/h2&gt;

&lt;p&gt;The number one enemy of a good change fail rate is poor testing practices. When teams are trying to deploy fast, it can be tricky to ensure each feature gets thorough testing and review. But how do you remedy that, while still keeping lead times short?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ephemeralenvironments.io" rel="noopener noreferrer"&gt;Ephemeral environments&lt;/a&gt; are an effective way to make sure your features get enough eyes (and automation) prior to staging. Since infrastructure wait times become nonexistent, you can test your features as soon as you’re done building them, and share them with all stakeholders to get sufficient feedback. Instead of going back to the drawing board, you can make all changes on the spot, and then run tests until your pipeline is green. Having multiple gates before production (and even staging) can inspire trust in every deployment, resulting in a low change fail rate.&lt;/p&gt;

&lt;p&gt;And Shipyard gives you the tools and automation you need to do exactly that! &lt;a href="https://shipyard.build/signup" rel="noopener noreferrer"&gt;Kick off a 30 day free trial&lt;/a&gt; and see for yourself. Your DORA metrics will thank you.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>softwaredevelopment</category>
      <category>microservices</category>
    </item>
  </channel>
</rss>
