<?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: Jan De Dobbeleer</title>
    <description>The latest articles on DEV Community by Jan De Dobbeleer (@jandedobbeleer).</description>
    <link>https://dev.to/jandedobbeleer</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%2F305%2F4be574aa-9c18-4356-bde7-2da417aef53f.PNG</url>
      <title>DEV Community: Jan De Dobbeleer</title>
      <link>https://dev.to/jandedobbeleer</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jandedobbeleer"/>
    <language>en</language>
    <item>
      <title>Oh My Posh ❤️ Claude Code</title>
      <dc:creator>Jan De Dobbeleer</dc:creator>
      <pubDate>Sun, 28 Dec 2025 14:28:00 +0000</pubDate>
      <link>https://dev.to/jandedobbeleer/oh-my-posh-claude-code-66f</link>
      <guid>https://dev.to/jandedobbeleer/oh-my-posh-claude-code-66f</guid>
      <description>&lt;p&gt;Terminal customization just got a lot smarter. Oh My Posh now integrates with &lt;a href="https://code.claude.com/" rel="noopener noreferrer"&gt;Claude Code&lt;/a&gt; through its &lt;a href="https://code.claude.com/docs/en/statusline" rel="noopener noreferrer"&gt;&lt;code&gt;statusline&lt;/code&gt; functionality&lt;/a&gt;, bringing real-time AI session information  and development context directly into your Claude Code prompt.&lt;/p&gt;

&lt;p&gt;This isn't just another segment: it's a bridge between your development workflow and AI-powered coding assistance.&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%2F9vf60nqt4ipulhq08rqw.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%2F9vf60nqt4ipulhq08rqw.png" alt="Claude Code" width="800" height="578"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Claude Code's &lt;code&gt;statusline&lt;/code&gt;?
&lt;/h2&gt;

&lt;p&gt;Claude Code's &lt;code&gt;statusline&lt;/code&gt; feature allows you to create custom status displays that appear at the bottom of the Claude Code interface, similar to how terminal prompts work in shells. The &lt;code&gt;statusline&lt;/code&gt; receives rich JSON data about your current AI session via stdin, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Model information&lt;/strong&gt;: Which Claude model you're using (Claude Sonnet, Claude Opus, etc.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Token usage&lt;/strong&gt;: Input/output tokens, context window utilization, and usage percentages&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost tracking&lt;/strong&gt;: Real-time cost calculations and session duration&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Workspace context&lt;/strong&gt;: Current and project directories&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Session metadata&lt;/strong&gt;: Unique session IDs and version information&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;statusline&lt;/code&gt; updates automatically when conversation messages change (throttled to every 300ms max), and Oh My posh creates the status display with full ANSI color support.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting Up the Integration
&lt;/h3&gt;

&lt;p&gt;Configuration is straightforward. Add this to your Claude Code settings:&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;"statusLine"&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;"oh-my-posh claude"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"padding"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&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;That's it! Oh My Posh will automatically detect when Claude Code provides session data and display the relevant information in your prompt.&lt;/p&gt;

&lt;p&gt;It's important to note that the &lt;code&gt;claude&lt;/code&gt; CLI command operates differently from your regular prompt configuration. When used as a &lt;code&gt;statusline&lt;/code&gt; command, Oh My Posh runs in a special mode that's completely separate from your standard terminal prompt. This means you'll likely want to create a dedicated, minimal configuration specifically for Claude Code that focuses on displaying AI session information rather than your usual prompt elements.&lt;/p&gt;

&lt;h3&gt;
  
  
  Custom configuration
&lt;/h3&gt;

&lt;p&gt;By default, the &lt;code&gt;oh-my-posh claude&lt;/code&gt; command provides a built-in &lt;code&gt;statusline&lt;/code&gt; that shows your current working directory, git context, active model name, and context window usage as a visual gauge. To customize this display, use the &lt;code&gt;--config&lt;/code&gt; flag to specify your own theme configuration file that includes a custom claude segment tailored to your preferences.&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;"statusLine"&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;"oh-my-posh claude --config ~/.claude.omp.json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"padding"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&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;Just make sure the configuration also leverages the data available in the &lt;code&gt;claude&lt;/code&gt; segment to visualize the stats you care about. As this isn't like a regular prompt integration, keep the &lt;code&gt;statusline&lt;/code&gt; a single line and use left and right aligned prompt blocks to play with.&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;"$schema"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"palette"&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;"black"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"#262B44"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"blue"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"#4B95E9"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"green"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"#59C9A5"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"orange"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"#F07623"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"red"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"#D81E5B"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"sapling"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"#a6d189"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"white"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"#E0DEF4"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"yellow"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"#F3AE35"&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;"accent_color"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"32"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"blocks"&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;"prompt"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"alignment"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"left"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"segments"&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;"options"&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;"dir_length"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"folder_separator_icon"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\u&lt;/span&gt;&lt;span class="s2"&gt;e0bb"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"style"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"fish"&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;"template"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"{{ if .Segments.Git.Dir }} &lt;/span&gt;&lt;span class="se"&gt;\u&lt;/span&gt;&lt;span class="s2"&gt;f1d2 &amp;lt;i&amp;gt;&amp;lt;b&amp;gt;{{ .Segments.Git.RepoName }}{{ if .Segments.Git.IsWorkTree }} &lt;/span&gt;&lt;span class="se"&gt;\u&lt;/span&gt;&lt;span class="s2"&gt;e21c{{ end }}&amp;lt;/b&amp;gt;&amp;lt;/i&amp;gt;{{ $rel :=  .Segments.Git.RelativeDir }}{{ if $rel }} &lt;/span&gt;&lt;span class="se"&gt;\u&lt;/span&gt;&lt;span class="s2"&gt;eaf7 {{ .Format $rel }}{{ end }}{{ else }} &lt;/span&gt;&lt;span class="se"&gt;\u&lt;/span&gt;&lt;span class="s2"&gt;ea83 {{ path .Path .Location }}{{ end }} "&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"foreground"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"p:white"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"leading_diamond"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\u&lt;/span&gt;&lt;span class="s2"&gt;e0b6"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"background"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"p:orange"&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;"path"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"style"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"diamond"&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;"options"&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;"branch_icon"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\u&lt;/span&gt;&lt;span class="s2"&gt;e0a0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"fetch_status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&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;"template"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;" {{ if .UpstreamURL }}{{ url .UpstreamIcon .UpstreamURL }} {{ end }}{{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Working.Changed }} &lt;/span&gt;&lt;span class="se"&gt;\u&lt;/span&gt;&lt;span class="s2"&gt;f044 {{ nospace .Working.String }}{{ end }}{{ if .Staging.Changed }} &lt;/span&gt;&lt;span class="se"&gt;\u&lt;/span&gt;&lt;span class="s2"&gt;f046 {{ .Staging.String }}{{ end }} "&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"foreground"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"p:black"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"leading_diamond"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;parentBackground,background&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;\u&lt;/span&gt;&lt;span class="s2"&gt;e0b0&amp;lt;/&amp;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;"trailing_diamond"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\u&lt;/span&gt;&lt;span class="s2"&gt;e0b4"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"background"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"p:green"&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;"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;"style"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"diamond"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"foreground_templates"&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;"{{ if or (.Working.Changed) (.Staging.Changed) }}p:black{{ end }}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="s2"&gt;"{{ if or (gt .Ahead 0) (gt .Behind 0) }}p:white{{ end }}"&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;"background_templates"&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;"{{ if or (.Working.Changed) (.Staging.Changed) }}p:yellow{{ end }}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="s2"&gt;"{{ if and (gt .Ahead 0) (gt .Behind 0) }}p:red{{ end }}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="s2"&gt;"{{ if gt .Ahead 0 }}#49416D{{ end }}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="s2"&gt;"{{ if gt .Behind 0 }}#7A306C{{ end }}"&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="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;"prompt"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"alignment"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"right"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"segments"&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;"leading_diamond"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\u&lt;/span&gt;&lt;span class="s2"&gt;e0b6"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"template"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;" &lt;/span&gt;&lt;span class="se"&gt;\u&lt;/span&gt;&lt;span class="s2"&gt;db82&lt;/span&gt;&lt;span class="se"&gt;\u&lt;/span&gt;&lt;span class="s2"&gt;dfc9 {{ .Model.DisplayName }} &lt;/span&gt;&lt;span class="se"&gt;\u&lt;/span&gt;&lt;span class="s2"&gt;f2d0 {{ .TokenUsagePercent.Gauge }} "&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"foreground"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"p:white"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"background"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"accent"&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;"claude"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"style"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"diamond"&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;"options"&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;"charged_icon"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\u&lt;/span&gt;&lt;span class="s2"&gt;e22f "&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"charging_icon"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\u&lt;/span&gt;&lt;span class="s2"&gt;e234 "&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"discharging_icon"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\u&lt;/span&gt;&lt;span class="s2"&gt;e231 "&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;"cache"&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;"duration"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"10m"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"strategy"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"session"&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;"leading_diamond"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;background,parentBackground&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;\u&lt;/span&gt;&lt;span class="s2"&gt;e0b2&amp;lt;/&amp;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;"trailing_diamond"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\u&lt;/span&gt;&lt;span class="s2"&gt;e0b4"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"template"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"{{ if not .Error }} {{ .Icon }}{{ .Percentage }}%{{ end }}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"foreground"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"#111111"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"background"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"accent"&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;"battery"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"style"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"diamond"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"background_templates"&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;"{{if eq &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;Discharging&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; .State.String}}p:orange{{end}}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="s2"&gt;"{{if eq &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;Full&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; .State.String}}p:green{{end}}"&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="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&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;h2&gt;
  
  
  The Claude Code segment
&lt;/h2&gt;

&lt;p&gt;Oh My Posh's new &lt;code&gt;claude&lt;/code&gt; segment taps into this &lt;code&gt;statusline&lt;/code&gt; data to bring AI session awareness directly into your terminal prompt. When you use the &lt;code&gt;oh-my-posh claude&lt;/code&gt; command as your &lt;code&gt;statusline&lt;/code&gt; command in Claude Code, you get access to a wealth of session information that can be displayed in your prompt without needing to know the technical details.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example Configuration
&lt;/h3&gt;

&lt;p&gt;Here's a sample configuration that shows the model name and context usage:&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;"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;"claude"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"style"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"diamond"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"leading_diamond"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\u&lt;/span&gt;&lt;span class="s2"&gt;e0b6"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"trailing_diamond"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\u&lt;/span&gt;&lt;span class="s2"&gt;e0b4"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"foreground"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"#FFFFFF"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"background"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"#FF6B35"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"template"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;" &lt;/span&gt;&lt;span class="se"&gt;\u&lt;/span&gt;&lt;span class="s2"&gt;db82&lt;/span&gt;&lt;span class="se"&gt;\u&lt;/span&gt;&lt;span class="s2"&gt;dfc9 {{ .Model.DisplayName }} &lt;/span&gt;&lt;span class="se"&gt;\u&lt;/span&gt;&lt;span class="s2"&gt;f2d0 {{ .TokenUsagePercent.Gauge }} "&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;This displays something like: &lt;code&gt;🤖 Claude 4.5 Sonnet  ▰▰▰▱▱&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The gauge provides instant visual feedback on how much of your context window you've consumed, which is crucial for managing long coding sessions.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Technical Details
&lt;/h2&gt;

&lt;p&gt;Under the hood, Oh My Posh reads the rich JSON session data that Claude Code provides via stdin when used as a &lt;code&gt;statusline&lt;/code&gt; command. The segment only activates when Claude Code session data is available, so there's no performance impact when you're not using Claude Code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;If you're already using Oh My Posh, adding Claude Code integration is as simple as:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install Claude Code if you haven't already&lt;/li&gt;
&lt;li&gt;Add the &lt;code&gt;statusline&lt;/code&gt; configuration to your Claude Code settings&lt;/li&gt;
&lt;li&gt;Optionally create your own configuration including the &lt;code&gt;claude&lt;/code&gt; segment&lt;/li&gt;
&lt;li&gt;Start a Claude Code session and watch your prompt come alive&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For detailed configuration options and all available properties, check out the &lt;a href="https://ohmyposh.dev/docs/segments/cli/claude" rel="noopener noreferrer"&gt;complete Claude segment documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next?
&lt;/h2&gt;

&lt;p&gt;This integration opens up exciting possibilities. Imagine prompts that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Change color based on token usage percentage&lt;/li&gt;
&lt;li&gt;Show different icons for different AI models&lt;/li&gt;
&lt;li&gt;Display cost warnings when sessions get expensive&lt;/li&gt;
&lt;li&gt;Integrate with any other segment to show additional development context&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The foundation is there, and now it's up to the community to build amazing configurations that make AI-powered development even more seamless.&lt;/p&gt;

</description>
      <category>claude</category>
      <category>ai</category>
      <category>terminal</category>
      <category>prompt</category>
    </item>
    <item>
      <title>Going beyond autocomplete with AI Agents</title>
      <dc:creator>Jan De Dobbeleer</dc:creator>
      <pubDate>Tue, 09 Dec 2025 09:18:04 +0000</pubDate>
      <link>https://dev.to/wildgoosedevelopers/going-beyond-autocomplete-with-ai-agents-1cee</link>
      <guid>https://dev.to/wildgoosedevelopers/going-beyond-autocomplete-with-ai-agents-1cee</guid>
      <description>&lt;p&gt;Over the past year, I’ve seen many software engineers and teams dive into AI adoption, only to face disappointment when the hype delivers little more than autocomplete tricks or basic unit test generation. The outputs often ignore standards, architecture, and conventions, creating more work instead of reducing it. Rather than abandoning this &lt;strong&gt;inevitable shift&lt;/strong&gt;, we should learn from those who succeed.&lt;/p&gt;

&lt;p&gt;What’s missing for those who struggle with AI adoption? It’s the ability to guide the model with context. Many tools allow you to automatically inject &lt;strong&gt;tailored instructions&lt;/strong&gt; for each task, shaping the output for success. In this post, I’ll demonstrate how to do this with GitHub Copilot and Claude Code, setting you on the path to becoming an AI-native software engineer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why instructions change everything
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;They make implicit team rules explicit and version-controlled.&lt;/li&gt;
&lt;li&gt;They steer the agent’s defaults: style, architecture, naming, testing, commit conventions, security guardrails.&lt;/li&gt;
&lt;li&gt;They raise consistency across the team and reduce review friction.&lt;/li&gt;
&lt;li&gt;They open the door towards more AI automation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When instructions live in-repo, the agent reads them like any engineer would—then generates code that fits your standards by default.&lt;/p&gt;

&lt;h2&gt;
  
  
  Instruction file types: tool-specific vs. universal
&lt;/h2&gt;

&lt;p&gt;Different AI tools support different instruction file conventions, but the underlying principles remain the same: provide context, enforce standards, and guide behaviour.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub Copilot&lt;/strong&gt; uses &lt;code&gt;.github/copilot-instructions.md&lt;/code&gt; for repository-wide instructions that apply to all requests. For more granular control, you can create path-specific instructions using &lt;code&gt;.github/instructions/*.instructions.md&lt;/code&gt; files with frontmatter scoping. These files can target specific paths, languages, or audiences (IDE vs. CLI), making them highly flexible for monorepos and polyglot projects.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Claude Code&lt;/strong&gt; looks for &lt;code&gt;CLAUDE.md&lt;/code&gt; in your project root. This single file contains all Claude-specific instructions, though you can organize complex guidance using markdown sections and headers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Universal approach&lt;/strong&gt;: Many teams adopt &lt;code&gt;AGENTS.md&lt;/code&gt; as a tool-agnostic convention. Place an &lt;code&gt;AGENTS.md&lt;/code&gt; file at the root or nested in directories, and any agent tool can consume it. This works well when you use multiple AI tools or want a single source of truth that isn't vendor-locked.&lt;/p&gt;

&lt;p&gt;The choice depends on your team's needs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;.github/copilot-instructions.md&lt;/code&gt; for simple, repository-wide Copilot guidance.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;.github/instructions/*.instructions.md&lt;/code&gt; when you need fine-grained, path-specific control.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;AGENTS.md&lt;/code&gt; for simplicity and portability across different AI tools.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now let's explore how to architect these instructions for maximum effectiveness.&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture: layering context so it stays relevant and cheap
&lt;/h2&gt;

&lt;p&gt;Think of context in layers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Global repository instructions&lt;/strong&gt;: High-level standards that apply everywhere (language style, testing baseline, security posture, commit messages, PR checklist).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Local, nested instructions&lt;/strong&gt;: Directory-scoped &lt;code&gt;AGENTS.md&lt;/code&gt; files or GitHub Copilot instruction files that apply to specific domains (e.g., backend/api vs. frontend/ui). These are only loaded when relevant, saving tokens and maintenance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Task-specific prompt files&lt;/strong&gt;: Small, reusable prompt templates for common jobs (e.g., "add endpoint", "migrate tests", "write changelog"). They eliminate boilerplate prompting and keep users on the happy path.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The result: less noise, lower cost, more accurate outputs.&lt;/p&gt;

&lt;h2&gt;
  
  
  In Practice
&lt;/h2&gt;

&lt;p&gt;Imagine a typical full-stack application: a React frontend talking to a Node.js API, each with distinct patterns. The frontend team enforces accessibility standards and component testing. The backend team requires validated payloads, structured error responses, and integration tests. Without instructions, an AI agent might generate a backend endpoint that returns raw errors or a frontend component missing ARIA labels — creating review friction and rework. Instruction files ensure the agent knows these domain-specific rules and conventions upfront.&lt;/p&gt;

&lt;h3&gt;
  
  
  File structure examples
&lt;/h3&gt;

&lt;p&gt;GitHub Copilot approach with &lt;code&gt;.github/&lt;/code&gt; directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;repo/
├── .github/
│   ├── copilot-instructions.md    # Repository-wide Copilot instructions
│   ├── instructions/               # Path-specific instruction files with frontmatter scopes
│   │   ├── backend.md
│   │   ├── frontend.md
│   │   └── security.md
│   └── prompts/                    # Task-specific prompt files (optional)
├── backend/
    └── frontend/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Universal &lt;code&gt;AGENTS.md&lt;/code&gt; approach (tool-agnostic):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;repo/
├── AGENTS.md                       # Repository-wide instructions
├── backend/
│   ├── AGENTS.md                   # Backend-specific instructions
│   └── api/
│       └── AGENTS.md               # API-specific instructions
└── frontend/
    └── AGENTS.md                   # Frontend-specific instructions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Example instruction files
&lt;/h3&gt;

&lt;p&gt;Repository-wide instructions (applies to entire codebase):&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;# Repository-wide Instructions&lt;/span&gt;

&lt;span class="gu"&gt;## Commits&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Use Conventional Commits (feat:, fix:, docs:, refactor:, test:, chore:)
&lt;span class="p"&gt;-&lt;/span&gt; Reference issue numbers in commit body (e.g., "Relates to #123")
&lt;span class="p"&gt;-&lt;/span&gt; Keep subject line under 72 characters

&lt;span class="gu"&gt;## Testing&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Require tests for all new features and bug fixes
&lt;span class="p"&gt;-&lt;/span&gt; Maintain minimum 80% code coverage
&lt;span class="p"&gt;-&lt;/span&gt; Run full test suite before submitting PR

&lt;span class="gu"&gt;## Code Review&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Keep PRs focused and under 400 lines when possible
&lt;span class="p"&gt;-&lt;/span&gt; Self-review checklist: tests pass, no secrets, lint clean
&lt;span class="p"&gt;-&lt;/span&gt; Tag at least one reviewer familiar with the domain

&lt;span class="gu"&gt;## Security&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Never commit secrets, API keys, or credentials
&lt;span class="p"&gt;-&lt;/span&gt; Use environment variables for configuration
&lt;span class="p"&gt;-&lt;/span&gt; Run security scanners in CI pipeline
&lt;span class="p"&gt;-&lt;/span&gt; Validate and sanitize all external inputs

&lt;span class="gu"&gt;## Documentation&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Update README when adding new features or changing setup
&lt;span class="p"&gt;-&lt;/span&gt; Document complex algorithms inline
&lt;span class="p"&gt;-&lt;/span&gt; Keep API documentation in sync with code changes

&lt;span class="gu"&gt;## Writing Style&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Always wrap filenames in backticks (e.g., &lt;span class="sb"&gt;`config.json`&lt;/span&gt;, &lt;span class="sb"&gt;`AGENTS.md`&lt;/span&gt;, &lt;span class="sb"&gt;`.github/copilot-instructions.md`&lt;/span&gt;)
&lt;span class="p"&gt;-&lt;/span&gt; Use clear, descriptive variable and function names
&lt;span class="p"&gt;-&lt;/span&gt; Write comments for non-obvious logic, not for self-explanatory code
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Backend-specific instructions:&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;Backend&lt;/span&gt;
&lt;span class="na"&gt;scope&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;paths&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;backend/**"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;languages&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;js"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ts"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;audience&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;ide"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cli"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="gh"&gt;# Backend API Standards&lt;/span&gt;

&lt;span class="gu"&gt;## Goals&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Add/modify API endpoints with proper validation, telemetry, and tests.

&lt;span class="gu"&gt;## Code style&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Follow repo ESLint/Prettier. Prefer functional handlers; avoid singletons.

&lt;span class="gu"&gt;## HTTP/Errors&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Use RFC7807 problem+json. Map domain errors to 4xx with stable codes.

&lt;span class="gu"&gt;## Testing&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; For each handler, add integration tests hitting the router; seed minimal fixtures.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Frontend-specific instructions:&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;Frontend&lt;/span&gt;
&lt;span class="na"&gt;scope&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;paths&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;frontend/**"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;languages&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;ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tsx"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;audience&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;ide"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cli"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="gh"&gt;# Frontend Engineering Standards&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Use React + Vite; prefer function components and hooks.
&lt;span class="p"&gt;-&lt;/span&gt; Enforce a11y: labels, roles, keyboard navigation.
&lt;span class="p"&gt;-&lt;/span&gt; Co-locate component tests next to components with &lt;span class="err"&gt;*&lt;/span&gt;.spec.tsx.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Key takeaways
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Keep each instruction file concise; multiple files may apply simultaneously.&lt;/li&gt;
&lt;li&gt;Scope narrowly by paths/languages to avoid conflicts and reduce tokens.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Instruction merging behavior:&lt;/strong&gt; Both GitHub Copilot and &lt;code&gt;AGENTS.md&lt;/code&gt; approaches merge path-specific/scoped instructions with repository-wide files. All applicable instruction files are combined and sent to the model together, enabling layered context that becomes more specific as you navigate deeper into the codebase.&lt;/li&gt;
&lt;li&gt;Frontmatter scoping (shown above) is specific to GitHub Copilot's &lt;code&gt;.github/instructions/&lt;/code&gt; files.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;AGENTS.md&lt;/code&gt; files use directory proximity for scoping instead of frontmatter.&lt;/li&gt;
&lt;li&gt;Both approaches achieve the same goal: context layering that keeps instructions relevant and maintainable.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Task automation: prompt files and sub-agents
&lt;/h2&gt;

&lt;p&gt;Beyond static instructions, both GitHub Copilot and Claude Code support structured, reusable task templates that guide common workflows. These eliminate repetitive prompting and ensure consistent outputs across your team.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prompt files&lt;/strong&gt; (GitHub Copilot) are parameterized markdown templates stored in a &lt;code&gt;prompts/&lt;/code&gt; directory. They define inputs, steps, and constraints for recurring tasks like &lt;em&gt;add API endpoint&lt;/em&gt; or &lt;em&gt;migrate tests&lt;/em&gt;. Users invoke them from the IDE or CLI, supply the parameters, and get guided, standardized results.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sub-agents&lt;/strong&gt; (Claude Code) work similarly but can be more dynamic. Each sub-agent focuses on a specific responsibility (e.g., &lt;em&gt;Security Review&lt;/em&gt;, &lt;em&gt;API Synthesizer&lt;/em&gt;) with its own instruction set. Claude can either route to the appropriate sub-agent automatically based on your task and the sub-agent's description, or you can invoke a specific sub-agent explicitly by name in your prompts.&lt;/p&gt;

&lt;p&gt;Both approaches serve the same purpose: turning common tasks into repeatable, version-controlled workflows.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prompt files (GitHub Copilot)
&lt;/h3&gt;

&lt;p&gt;Create a &lt;code&gt;prompts/&lt;/code&gt; directory (see &lt;a href="https://code.visualstudio.com/docs/copilot/customization/prompt-files" rel="noopener noreferrer"&gt;VS Code Copilot Prompt Files&lt;/a&gt;) with reusable task prompts.&lt;/p&gt;

&lt;p&gt;Prompt files can be stored in two locations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Workspace-level&lt;/strong&gt;: &lt;code&gt;.github/prompts/&lt;/code&gt; (available in current workspace only)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;User-level&lt;/strong&gt;: VS Code profile folder (available across all workspaces, syncable via Settings Sync)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;prompts/
├── add-endpoint.md
├── migrate-tests.md
└── write-changelog.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example prompt file with frontmatter:&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;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Create an API endpoint with validation, tests, and docs&lt;/span&gt;
&lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;agent&lt;/span&gt;
&lt;span class="na"&gt;tools&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;githubRepo'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;search/codebase'&lt;/span&gt;&lt;span class="pi"&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;Claude Sonnet &lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

Use the repository's Backend instructions.
Add ${input:method} ${input:route} with validation and router-level tests.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Usage:&lt;/strong&gt; In VS Code, use the &lt;code&gt;/&lt;/code&gt; command in chat to invoke prompts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/add-endpoint method=POST route=/api/users
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The prompt file parameters are filled automatically, and Copilot generates code following the template's instructions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sub-agents (Claude Code)
&lt;/h3&gt;

&lt;p&gt;See &lt;a href="https://code.claude.com/docs/en/sub-agents" rel="noopener noreferrer"&gt;Claude Code: Sub-agents&lt;/a&gt; for detailed configuration. Each sub-agent can have its own focused instruction set and optional scope restrictions.&lt;/p&gt;

&lt;p&gt;Just like prompt files, sub-agents can be stored in two locations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Project-level&lt;/strong&gt;: &lt;code&gt;.claude/agents/&lt;/code&gt; (available in current project only)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;User-level&lt;/strong&gt;: &lt;code&gt;~/.claude/agents/&lt;/code&gt; (available across all projects)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example sub-agent configuration:&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;add-endpoint&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 API endpoints with validation, tests, and documentation. Use proactively after modifying backend code.&lt;/span&gt;
&lt;span class="na"&gt;tools&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Read, Edit, Bash, Grep, Glob&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;inherit&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

Use the repository's Backend instructions.
Add endpoints with validation and router-level tests.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Usage:&lt;/strong&gt; Invoke sub-agents explicitly by mentioning them with &lt;code&gt;@&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@add-endpoint Create a POST /api/users endpoint
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or let Claude route automatically by describing the task without specifying a sub-agent. Claude will select the appropriate sub-agent based on context and task requirements.&lt;/p&gt;

&lt;h2&gt;
  
  
  Instruction writing and refinement
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Start with generic, widely available best-practice instructions
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Use markdown header for emphasis and agent guidance.&lt;/li&gt;
&lt;li&gt;Keep instructions concise and to the point.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Goal:&lt;/strong&gt; Establish a baseline and understand prompting techniques.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TIP&lt;/strong&gt; Get inspiration from the &lt;a href="https://github.com/github/awesome-copilot/tree/main/instructions" rel="noopener noreferrer"&gt;awesome-copilot repository&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Meta Prompting → Model driven refinement
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Use your AI tool to generate/refine instructions based on your repository's context.&lt;/li&gt;
&lt;li&gt;Ask the model to remove ambiguity and keep instructions concise.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Goal:&lt;/strong&gt; Generate prompts that are understandable by the AI agent.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Example:&lt;/strong&gt; Generate me Copilot instructions for my blog post content based on the style you find in the current posts inside /content/post*.md. Validate for ambiguity and keep the instructions concise.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TIP&lt;/strong&gt; Use Visual Studio Code's built-in &lt;strong&gt;Generate Workspace Instructions File&lt;/strong&gt; to get an out of the box prompt that generates the instructions file based on your repository's context.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Meta + Feedback → Self-analysis &amp;amp; future adjustment
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;After generating output, ask the model to explain deviations from guidelines and adjust its approach for future tasks by modifying the instructions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Goal:&lt;/strong&gt; Build a feedback loop for continuous improvement.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Example:&lt;/strong&gt; Go through our conversation and iterations we made and implement/adjust instructions to avoid these mistakes in the future.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Making agentic AI work for you
&lt;/h2&gt;

&lt;p&gt;The difference between autocomplete on steroids and genuinely transformative AI assistance isn't the model — it's the context you provide. Teams who succeed with AI agents don't just adopt the tools; they codify their implicit knowledge into explicit, version-controlled instructions. They start by inventorying their domain rules and standards, then layer them strategically: repository-wide baselines, domain-specific guidance, and task-focused prompts. They keep these instructions close to the code, maintain them like any other asset, and refine them through feedback loops.&lt;/p&gt;

&lt;p&gt;This isn't optional groundwork for some future state of AI development. It's the necessary first step that transforms AI from a novelty into a reliable engineering partner. Without it, you're asking agents to guess your standards. With it, you're building a foundation for automation that scales across your team and compounds over time.&lt;/p&gt;

&lt;h2&gt;
  
  
  References and further reading
&lt;/h2&gt;

&lt;p&gt;References:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://code.visualstudio.com/docs/copilot/customization/prompt-files" rel="noopener noreferrer"&gt;VS Code Copilot Prompt Files&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://code.claude.com/docs/en/sub-agents" rel="noopener noreferrer"&gt;Claude Code: Sub-agents&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/live/IqWfKj4mUIo?t=737&amp;amp;si=cKd-_sLuis78eY_K" rel="noopener noreferrer"&gt;Lovable prompting techniques&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>prompts</category>
      <category>githubcopilot</category>
      <category>claude</category>
    </item>
    <item>
      <title>Do tattoos influence the probability of getting hired?</title>
      <dc:creator>Jan De Dobbeleer</dc:creator>
      <pubDate>Sat, 09 Jun 2018 05:20:38 +0000</pubDate>
      <link>https://dev.to/jandedobbeleer/do-tattoos-influence-the-probability-of-being-hired-j8n</link>
      <guid>https://dev.to/jandedobbeleer/do-tattoos-influence-the-probability-of-being-hired-j8n</guid>
      <description>&lt;p&gt;Saw this one on &lt;a href="https://twitter.com/xira_infotech/status/1005299940715741184" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; and immediately thought of sharing it here because I'm really curious about the responses.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Does having tattoos influence the probability of being hired as a developer/programmer?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;My status: I have a full sleeve on my right arm and one other visible tattoo on my left arm. So far, I haven't had any negative experiences with recruiting within IT, but that might be directly related to the type of companies and cultures I'm engaging with.&lt;/p&gt;

&lt;p&gt;If you have tattoos, what are your experiences? Or maybe you don't but know about a policy at work? Or, maybe, just maybe, you've got an opinion about this topic? Share away!&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>career</category>
    </item>
    <item>
      <title>A viable alternative to Operator Mono in Visual Studio Code</title>
      <dc:creator>Jan De Dobbeleer</dc:creator>
      <pubDate>Fri, 01 Jun 2018 18:35:25 +0000</pubDate>
      <link>https://dev.to/jandedobbeleer/a-viable-alternative-to-operator-mono-in-visual-studio-code-ge8</link>
      <guid>https://dev.to/jandedobbeleer/a-viable-alternative-to-operator-mono-in-visual-studio-code-ge8</guid>
      <description>&lt;p&gt;After seeing &lt;a href="https://marketplace.visualstudio.com/items?itemName=sdras.night-owl&amp;amp;WT.mc_id=twitter-social-sdras" rel="noopener noreferrer"&gt;Night Owl&lt;/a&gt;, a color theme for VSCode created by &lt;a href="https://twitter.com/sarah_edo/status/997238414390022144" rel="noopener noreferrer"&gt;Sarah Drasner&lt;/a&gt; &lt;strong&gt;leveraging the use of italics&lt;/strong&gt; and a font supporting this, I was hesitant about either pruchasing Dank Mono (less mature, but already super nice Operator Mono alternative), or start the search for free alternative. Given that it's in my nature to switch interests every two seconds, I made the call not to spend money on a hype, but instead look for hacks which must surely be out there.&lt;/p&gt;

&lt;p&gt;At first, my search for free alternatives to Operator Mono guided me towards &lt;a href="https://github.com/kencrocken/FiraCodeiScript" rel="noopener noreferrer"&gt;FiraCodeiScript&lt;/a&gt; made by Ken Krocken. What it does is make two fonts look like one, so you have Fira Code as the regular font and Script12 as the italic font. They were edited using &lt;a href="https://fontforge.github.io" rel="noopener noreferrer"&gt;FontForge&lt;/a&gt;, a tool used to create or alter fonts. My first impression was &lt;em&gt;That's pretty cool&lt;/em&gt;, but after a while I couldn't help but not really liking Script12.&lt;/p&gt;

&lt;p&gt;I figured I had to &lt;strong&gt;create my own version&lt;/strong&gt;. As I'm a programmer, I didn't want to mess with a GUI tool and decided to go for a Python script using &lt;a href="https://github.com/fonttools/fonttools" rel="noopener noreferrer"&gt;FontTools&lt;/a&gt; to edit the font files and make them appear as one font family. The information on how to do this is available in the following &lt;a href="https://github.com/open-source-ideas/open-source-ideas/issues/10#issuecomment-360999485" rel="noopener noreferrer"&gt;issue&lt;/a&gt; on the Open Soure Idea's repository on GitHub.&lt;/p&gt;

&lt;p&gt;FontTools turned out to work against rather than with me, for some reason I couldn't always figure out where to find the fields I needed to adjust. &lt;strong&gt;The quest for a better module began&lt;/strong&gt;. My terminal fonts always come from the &lt;a href="https://github.com/ryanoasis/nerd-fonts" rel="noopener noreferrer"&gt;Nerd Fonts&lt;/a&gt; repository, and as they also need to rename fonts due to licensing issues, it was the best place to start digging.&lt;/p&gt;

&lt;p&gt;They use a &lt;a href="https://github.com/ryanoasis/nerd-fonts/blob/master/font-patcher" rel="noopener noreferrer"&gt;Python script&lt;/a&gt; to edit the font files and append loads of cool stuff, and guess what, it's using the Python module included in FontForge. Cool! Easy, right? Nope. I'm using Windows 10 by choice and this time, it hit me in the nuts. You can't install the module using &lt;code&gt;pip install FontForge&lt;/code&gt;, it's included in the installation of FontForge. On Linux you can install bindings to expose the module and use it in your scripts, but there's no such option for Windows.&lt;/p&gt;

&lt;p&gt;Back to the thinking cabin! Looking at how FontForge works, it embeds Python 2.7 (🤦‍) which gives you the FontForge module out of the box. Being pragmatic and all, I decided to use that Python executable to create the script. Using VSCode, you can adjust your debug settings (located at &lt;code&gt;projectroot\.vscode\launch.json&lt;/code&gt;) to do just that.&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="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Use&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;IntelliSense&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;learn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;about&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;possible&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;attributes.&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Hover&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;view&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;descriptions&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;existing&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;attributes.&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;For&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;more&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;information&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;visit:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;https://go.microsoft.com/fwlink/?linkid=&lt;/span&gt;&lt;span class="mi"&gt;830387&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0.2.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"configurations"&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;"name"&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 Experimental: Current File (Integrated Terminal)"&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;"pythonExperimental"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"request"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"launch"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"program"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"${file}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"console"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"integratedTerminal"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"pythonPath"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"C:&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;Program Files (x86)&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;FontForgeBuilds&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;bin&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;ffpython.exe"&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;This way you can &lt;em&gt;easily&lt;/em&gt; import the FontForge module and create a script that alterts two font files to a newly invented font family. I really like Fira Code, so I downloaded &lt;a href="https://github.com/ryanoasis/nerd-fonts/tree/master/patched-fonts/FiraCode/Regular/complete" rel="noopener noreferrer"&gt;Fura Code&lt;/a&gt; from Nerd Fonts to hold all interesting bits and pieces, and fell in love with &lt;a href="https://fonts.google.com/specimen/Yellowtail" rel="noopener noreferrer"&gt;Yellowtail&lt;/a&gt; to use as the italic variant.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;fontforge&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;uuid&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;change_font_data_and_save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;font_location&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;familyname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                              &lt;span class="n"&gt;sub_family&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;output_dir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;uid&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;source_font&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fontforge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;font_location&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;source_font&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;familyname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;familyname&lt;/span&gt;
    &lt;span class="n"&gt;source_font&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fullname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;{} {}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;familyname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sub_family&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;source_font&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fontname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;{}-{}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;familyname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sub_family&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;source_font&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendSFNTName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;English (US)&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Family&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                               &lt;span class="n"&gt;source_font&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;familyname&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;source_font&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendSFNTName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;English (US)&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;SubFamily&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                               &lt;span class="n"&gt;sub_family&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;source_font&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendSFNTName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;English (US)&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;UniqueID&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                               &lt;span class="n"&gt;uid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;source_font&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendSFNTName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;English (US)&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Preferred Family&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                               &lt;span class="n"&gt;source_font&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;familyname&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;source_font&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendSFNTName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;English (US)&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Compatible Full&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                               &lt;span class="n"&gt;source_font&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fullname&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;source_font&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output_dir&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;source_font&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fullname&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;.ttf&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                         &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;opentype&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;PfEd-comments&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;


&lt;span class="n"&gt;regular_font&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;path_to_fura_code.tff&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="n"&gt;italic_font&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;path_to_yellowtail.ttf&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="n"&gt;output_dir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;./output&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="n"&gt;familyname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;VSCode Font&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="n"&gt;uid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;uuid4&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="nf"&gt;change_font_data_and_save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;regular_font&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;familyname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Regular&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;output_dir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;uid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;change_font_data_and_save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;italic_font&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;familyname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Italic&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;output_dir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;uid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This works like a charm, you get two fonts in the output folder which you can then install as one font family, adjust VSCode to use that font and profit. With &lt;strong&gt;one annoying side-effect&lt;/strong&gt;. Depending on the difference between the two fonts, you might need to scale one of them. I did so for Yellowtail resulting in some letters being chopped off when a sentence start with an italic word. In the sample above, whenever &lt;code&gt;def&lt;/code&gt; was on position 0 of a line, the &lt;code&gt;d&lt;/code&gt; is slightly cut off at the beginning. I don't need to explain this is not a desired effect.&lt;/p&gt;

&lt;p&gt;I went to have a look at the other custom fonts and &lt;strong&gt;they all have the same issue&lt;/strong&gt; depending on the font they use. An alternative solution which works a lot better is to use the &lt;a href="https://github.com/be5invis/vscode-custom-css" rel="noopener noreferrer"&gt;Custom CSS and JS plugin&lt;/a&gt; to alter the font size when a word is italic (can be distinguished by the &lt;code&gt;mkti&lt;/code&gt; class). But, and this is important, if we do this, then we lose the use-case for a custom font.&lt;/p&gt;

&lt;p&gt;So, after losing a few hours to get this right, I went for the custom CSS solution. I installed all variants of Fura Code and the Yellowtail font and created an override for the &lt;code&gt;mkti&lt;/code&gt; class using the Custom CSS and JS plugin. To do so, create a file with the following content. Alter the font family per your liking, after playing with a few handwritten fonts, I went for &lt;a href="https://www.dafont.com/flottflott.font" rel="noopener noreferrer"&gt;Flottflott&lt;/a&gt; in the end.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.mtki&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.6em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Flottflott&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will make the text bigger, but still respect the bounds of the window. So you get the same result font wise, but better. If you're on Windows, make sure to run VSCode elevated when applying the style (and re-applying whenever you update VSCode).&lt;/p&gt;

&lt;p&gt;On to theming. We all use different themes, and not every theme has support for italic keywords. Now, instead of creating a custom theme, I want to teach you how to override the theme settings so that they will be applied no matter the theme you're using. I switch themes like clothes (you can define whether that applies a lot or not 😲), so I don't want to go fiddling with this every time.&lt;/p&gt;

&lt;p&gt;As it turns out, VSCode adheres to the TextMate grammer syntax to define how it needs to render code. I found a nice &lt;a href="https://www.sublimetext.com/docs/3/scope_naming.html" rel="noopener noreferrer"&gt;guide&lt;/a&gt; from another undisclosed editor, which, in combination with looking at existing themes and how they do it, allowed me to get started. Currently my config looks like this.&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="nl"&gt;"editor.fontFamily"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"FuraCode NF"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"editor.fontLigatures"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"vscode_custom_css.imports"&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;"file://C:/Users/jan/.vscode_css_settings.css"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"vscode_custom_css.policy"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"editor.tokenColorCustomizations"&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;"textMateRules"&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;"scope"&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;"storage.modifier"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"variable.language"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"markup.italic"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"punctuation.definition.keyword"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"keyword.control.import"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"storage.type.class"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"storage.type.function"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"storage.modifier"&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;"settings"&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;"fontStyle"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"italic"&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="nl"&gt;"scope"&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="err"&gt;//following&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;will&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;be&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;excluded&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;italics&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"comment"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"invalid"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"keyword.operator"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"keyword.control.conditional"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"storage.type.function.arrow.js"&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;"settings"&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;"fontStyle"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&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="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are two overrides, one that explicitly says what to render italic (and thus add the &lt;code&gt;mkti&lt;/code&gt; class), and another to exclude keywords from being rendered italic. This way I can use whatever theme I like, my settings will make the right words appear italic and pretty. This list isn't complete, there are a lot more which can be added. In the end it depends on the theme, language and personal taste to define what it needs to look like.&lt;/p&gt;

&lt;p&gt;I hope you'll have as much fun customizing your editor as I had trying to find a silver bullet 😄.&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%2Fblog.itdepends.be%2Fimg%2Fitalic.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%2Fblog.itdepends.be%2Fimg%2Fitalic.png" alt="italic" width="800" height="144"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Originally posted at: &lt;a href="https://blog.itdepends.be/operator-mono-alternative/" rel="noopener noreferrer"&gt;https://blog.itdepends.be/operator-mono-alternative/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>programming</category>
      <category>productivity</category>
      <category>tutorial</category>
      <category>css</category>
    </item>
    <item>
      <title>Dotnet Core served with a slice of Cake</title>
      <dc:creator>Jan De Dobbeleer</dc:creator>
      <pubDate>Tue, 29 May 2018 07:12:01 +0000</pubDate>
      <link>https://dev.to/jandedobbeleer/dotnet-core-served-with-a-slice-of-cake-5972</link>
      <guid>https://dev.to/jandedobbeleer/dotnet-core-served-with-a-slice-of-cake-5972</guid>
      <description>&lt;p&gt;While preparing slides for an introduction into DevOps I was about to give to a bunch of knowledge eager .NET developers, I was looking to build a sample project to illustrate a nice setup to start with. DotNet Core was a given, with it's great CLI interface and ability to run everywhere, &lt;strong&gt;the choice was obvious&lt;/strong&gt;. But when it came to build tools, I felt that the ones I knew (psake, fake), could easily startle people new to this whole &lt;em&gt;build .NET code outside of Visual Studio&lt;/em&gt; kind of thing. There was one kid on the block which had been on my list to look at for quite a while, and  you know &lt;strong&gt;how much I love sidetracking&lt;/strong&gt; and spending way too much time exploring exciting new stuff!&lt;/p&gt;

&lt;p&gt;Long story short, I fell in love with Cake. Compared to other build automation tools, it comes with a lot of nice first- and third-party integrations, reducing the need for boilerplate code. Before, I made use of &lt;strong&gt;heavily customized PowerShell scripts&lt;/strong&gt; for versioning and uploading of artifacts and test results, Cake comes with all of that out of the box. Another advantage, if the feature you're looking isn't available, it's easily extensible. All the wins \0/.&lt;/p&gt;

&lt;p&gt;So, what would my ideal setup look like? Well, we need a few things when it comes to a nice CI setup. First, I want all the build logic to be managed from the source code, no dependencies in the GUI as it easily becomes a burden to maintain and switch context. On the plus side, we want to be able to run it locally as well as on our build agent, and Cake will help us achieve exactly that. Secondly, here's a list of stuff I'm looking for that Cake should handle for me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Split the build logic in tasks&lt;/li&gt;
&lt;li&gt;Group tasks to allow different types of builds&lt;/li&gt;
&lt;li&gt;Provide standard build functionality (clean, restore, build)&lt;/li&gt;
&lt;li&gt;Restore NuGet packages&lt;/li&gt;
&lt;li&gt;Enable static code analysis and linting&lt;/li&gt;
&lt;li&gt;Run unit tests and upload coverage&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's have a look at each of those.&lt;/p&gt;

&lt;h2&gt;
  
  
  Split the build logic in tasks
&lt;/h2&gt;

&lt;p&gt;To get started with Cake, you can make use of the &lt;a href="https://cakebuild.net/docs/tutorials/setting-up-a-new-project" rel="noopener noreferrer"&gt;bootstrappers&lt;/a&gt;. There are two versions, one for Windows, and one for Unix systems. I added both in my sample project, just make sure to use the correct line endings on each platform, or &lt;strong&gt;go for LF everywhere&lt;/strong&gt; (yeah, I said it). If you're using Visual Studio Code, feel free to have a look at the &lt;a href="https://marketplace.visualstudio.com/items?itemName=cake-build.cake-vscode" rel="noopener noreferrer"&gt;Cake extension&lt;/a&gt;, Gary Ewan Park even made &lt;a href="https://www.youtube.com/playlist?list=PL84yg23i9GBg7_7an5Qbo0Qllg-l2e-q-" rel="noopener noreferrer"&gt;accompanying videos&lt;/a&gt; to explain its capabilities.&lt;/p&gt;

&lt;p&gt;After installing a bootstrapper, make sure to pin the Cake version. You can do so by adding a file at &lt;code&gt;tools/packages.config&lt;/code&gt; with the following content.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;packages&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;package&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"Cake"&lt;/span&gt; &lt;span class="na"&gt;version=&lt;/span&gt;&lt;span class="s"&gt;"0.27.2"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/packages&amp;gt;&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;With all this in place we have the following files, other than the project files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.
build.ps1
build.sh
tools
- packages.config
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remember, we've got a DotNet Core project set up, in case you don't have one, feel free to clone the &lt;a href="https://github.com/JanDeDobbeleer/dotnet-core-sample" rel="noopener noreferrer"&gt;sample project&lt;/a&gt; to follow along. The purpose of the bootstrapper files &lt;code&gt;build.ps1&lt;/code&gt; and &lt;code&gt;build.sh&lt;/code&gt; is to be able to &lt;strong&gt;resolve all dependencies&lt;/strong&gt;, including Cake, and not having to worry about any of that. You can have a look at the source to see what they do, but the file we're really interested in is &lt;code&gt;build.cake&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Create the &lt;code&gt;build.cake&lt;/code&gt; file which will contain al our build logic from now on. The Cake website provides a nice &lt;a href="https://cakebuild.net/docs/tutorials/setting-up-a-new-project" rel="noopener noreferrer"&gt;getting started&lt;/a&gt; sample, so let's build from there.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;Argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"target"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Default"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nf"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Default"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Does&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;Information&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello World!"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nf"&gt;RunTarget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see we've met the first requirement. We have the ability to define tasks that can contain whatever logic we need. Written entirely in C#, this is a huge advantage and &lt;strong&gt;reduces the startup cost&lt;/strong&gt; as a .NET developer. The task called &lt;code&gt;Default&lt;/code&gt; is the one that runs when no parameters are defined. You can immediately see what it does by using the bootstrapper in your CLI tool of choice: &lt;code&gt;./build.ps1&lt;/code&gt; (but seriously, use &lt;a href="https://conemu.github.io/" rel="noopener noreferrer"&gt;ConEmu&lt;/a&gt;). The output looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Preparing to run build script...
Running build script...

========================================
Default
========================================
Hello World!

Task                          Duration
--------------------------------------------------
Default                       00:00:00.0136945
--------------------------------------------------
Total:                        00:00:00.0136945
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Group tasks to allow different types of builds
&lt;/h2&gt;

&lt;p&gt;Using Cake, it's easy to group a few tasks as one. Let's say we want to split our Hello world task into two meaningful ones and assign the combination as the &lt;code&gt;Default&lt;/code&gt;.&lt;br&gt;
We can define separate tasks and have &lt;code&gt;Default&lt;/code&gt; depend on both of them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;Argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"target"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Default"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nf"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Does&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;Information&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nf"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"World"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Does&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;Information&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"World"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nf"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Default"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsDependentOn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsDependentOn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"World"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nf"&gt;RunTarget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;When you run this using &lt;code&gt;./build.ps1&lt;/code&gt;, you can see both tasks being executed. Now that we understand the basics, it's time to implement the actual logic for our DotNet Core app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Provide standard build functionality (clean, restore, build)
&lt;/h2&gt;

&lt;p&gt;Cake provides support for DotNet Core via a built-in third party &lt;a href="https://cakebuild.net/dsl/dotnetcore/" rel="noopener noreferrer"&gt;plugin&lt;/a&gt;. To clean a project, you can make use of &lt;code&gt;DotNetCoreClean&lt;/code&gt;, but in my case, as I'm used to cleaning up after myself, I used a &lt;a href="https://github.com/JanDeDobbeleer/dotnet-core-sample/blob/master/build.cake#L40" rel="noopener noreferrer"&gt;custom implementation&lt;/a&gt; in the sample project. The main reason is that there's a lot more output coming from a build than the output from MSBuild, and I want to make sure everything is nice and tidy. In case you'd opt for the built-in, the task would look something like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="nf"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Clean"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Does&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;DotNetCoreClean&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"./src/project"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remember, you can do anything you want here, so maybe you're fine with this, or prefer a more custom approach, the choice is yours.&lt;/p&gt;

&lt;p&gt;The approach to restore nuget packages and build the projects is almost identical other than having the ability to define a few settings. You can find all information on the Cake &lt;a href="https://cakebuild.net/dsl/dotnetcore/" rel="noopener noreferrer"&gt;website&lt;/a&gt;, or have a peek at &lt;a href="https://github.com/JanDeDobbeleer/dotnet-core-sample/blob/master/build.cake#L72" rel="noopener noreferrer"&gt;the sample project&lt;/a&gt; for inspiration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enable static code analysis and linting
&lt;/h2&gt;

&lt;p&gt;Now that we have our base setup ready, we finally get to the interesting bits. When we think about .NET and code analysis, I hope you can't help but think about Resharper. By coincidence, JetBrains provides &lt;strong&gt;two CLI tools&lt;/strong&gt; &lt;a href="https://www.jetbrains.com/help/resharper/ReSharper_Command_Line_Tools.html" rel="noopener noreferrer"&gt;&lt;/a&gt;, inspectCode and dupFinder. The first one handles all checks included in Resharper, the second one will look for duplicate code blocks. &lt;strong&gt;The cool thing is&lt;/strong&gt; that we can make it validate the same ruleset we enforce via Visual Studio, by saving them to your project's &lt;code&gt;DotSettings&lt;/code&gt; file. You can read more about that &lt;a href="https://www.jetbrains.com/help/resharper/Sharing_Configuration_Options.html" rel="noopener noreferrer"&gt;here&lt;/a&gt;, we'll be using the 'Solution team-shared' layer in this sample.&lt;/p&gt;

&lt;p&gt;What might also be good to know is that Resharper in Visual Studio provides support for &lt;a href="http://editorconfig.org/" rel="noopener noreferrer"&gt;.editorconfig&lt;/a&gt; files, but those can't be used in combination with the CLI version. I spent about an hour trying to get it to work to finally come to that conclusion with the help of &lt;a href="https://twitter.com/maartenballiauw/status/988094504531095552" rel="noopener noreferrer"&gt;Maarten Balliauw&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To use these tools in our Cake script, we need a few dependencies. First of all, and maybe that's not at all a problem in your case, we need the &lt;a href="https://chocolatey.org/packages/visualstudio2017buildtools/15.2.26430.20170605" rel="noopener noreferrer"&gt;Visual Studio build tools&lt;/a&gt; and enable DotNet Core suppport. As &lt;strong&gt;a developer who only uses Visual Studio Code&lt;/strong&gt;, I did not have these preinstalled, causing a lot of pain and unclear errors. So, if you're like me, install these on your host or build machine if that's not already the case. Secondly we can make use of a Cake plugin called, you guessed it, &lt;a href="https://cakebuild.net/dsl/resharper/" rel="noopener noreferrer"&gt;Resharper&lt;/a&gt;. To include it, add the following line on top of your &lt;code&gt;build.cake&lt;/code&gt; script. This will make the bootstrapper resolve the dependency when running Cake.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#tool "nuget:https://www.nuget.org/api/v2?package=JetBrains.ReSharper.CommandLineTools&amp;amp;version=2018.1.0"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure to &lt;strong&gt;lock the version number&lt;/strong&gt; of external dependencies to avoid unwanted side effects. Updates to these tools should always be validated beforehand.&lt;/p&gt;

&lt;p&gt;All that's left is to create tasks to validate our code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="nf"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DupFinder"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Find duplicates in the code"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Does&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;DupFinderSettings&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;ShowStats&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;ShowText&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;OutputFile&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;$"&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;artifactsDir&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/dupfinder.xml"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;ExcludeCodeRegionsByNameSubstring&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"DupFinder Exclusion"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;ThrowExceptionOnFindingDuplicates&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="nf"&gt;DupFinder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"./App.sln"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nf"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"InspectCode"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Inspect the code using Resharper's rule set"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Does&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;InspectCodeSettings&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;SolutionWideAnalysis&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;OutputFile&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;$"&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;artifactsDir&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/inspectcode.xml"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;ThrowExceptionOnFindingViolations&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="nf"&gt;InspectCode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"./App.sln"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It will use our &lt;code&gt;DotSettings&lt;/code&gt; file out of the box, so no need to specify it. You can look at the &lt;a href="https://github.com/JanDeDobbeleer/dotnet-core-sample/blob/master/App.sln.DotSettings" rel="noopener noreferrer"&gt;sample&lt;/a&gt; to see the syntax, if you need to know where to find the names for these rules, have a look at the &lt;a href="https://www.jetbrains.com/help/resharper/Reference__Code_Inspections_CSHARP.html" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We can add another interesting tool caled DependenciesAnalyser. It will look at your nuget dependencies and see if they are outdated. It won't fail the build but it's such a good thing to include as &lt;strong&gt;you might otherwise forget&lt;/strong&gt; about this (I know I do). When I run it at the time of writing, it provides the following ouput, telling me I can update two dependencies.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;EDIT:&lt;/strong&gt; It seems this makes the UNIX builds &lt;a href="https://ci.appveyor.com/project/JanJoris/dotnet-core-sample/build/1.0.18/job/ijjicjy5joieu8jn" rel="noopener noreferrer"&gt;fail&lt;/a&gt;. I created an &lt;a href="https://github.com/joaoasrosa/dotnet-project-dependencies-analyser/issues/12" rel="noopener noreferrer"&gt;issue&lt;/a&gt; on the project to remind myself to have a look. For the time being I removed the task from the sample.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;========================================
Analyse-Dependencies
========================================
Executing task: Analyse-Dependencies
Resolving assembly Domain.XmlSerializers, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null
---------------------------------
Project: ./App\App.csproj
---------------------------------

---------------------------------
Project: ./Test\Test.csproj
coverlet.msbuild is on version 2.0.0. The dependency is outdated.
FluentAssertions is on version 5.3.0. The dependency is up-to-date.
Microsoft.NET.Test.Sdk is on version 15.7.2. The dependency is outdated.
xunit is on version 2.3.1. The dependency is up-to-date.
xunit.runner.visualstudio is on version 2.3.1. The dependency is up-to-date.
---------------------------------

Finished executing task: Analyse-Dependencies
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For convenience we can group these as one Task, to facilitate running the checks separately when needed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="nf"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Validate"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Validate code quality using Resharper CLI. tools."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsDependentOn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Analyse-Dependencies"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsDependentOn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DupFinder"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsDependentOn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"InspectCode"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Run unit tests and upload coverage
&lt;/h2&gt;

&lt;p&gt;Writing unit tests has always been a pleasure on DotNet. My base setup consists of a few winners (&lt;em&gt;opinion&lt;/em&gt;, it's my blog after all) like &lt;a href="https://xunit.github.io/" rel="noopener noreferrer"&gt;xUnit&lt;/a&gt; and &lt;a href="https://fluentassertions.com/" rel="noopener noreferrer"&gt;Fluent Assertions&lt;/a&gt;. Creating a test project can be done using the &lt;code&gt;dotnet new xunit&lt;/code&gt; command, and installing packages follows the &lt;code&gt;dotnet add package FluentAssertions&lt;/code&gt; syntax. You can run the tests using &lt;code&gt;dotnet test&lt;/code&gt;. A sample setup and explanation can be found on &lt;a href="https://docs.microsoft.com/en-us/dotnet/core/testing/unit-testing-with-dotnet-test" rel="noopener noreferrer"&gt;Microsoft's website&lt;/a&gt; if you need a more in-depth introduction.&lt;/p&gt;

&lt;p&gt;Cake provides the same ease of use compared to the other standard DotNet Core functionality, which makes our task look like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="nf"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Test"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Run all unit tests within the project."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Does&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;DotNetCoreTest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"./Test/Test.csproj"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, this gives us the ability to run unit tests, but how about calculating code coverage? It turns out there's an MSBuild extension that enables just that. It's called &lt;a href="https://github.com/tonerdo/coverlet" rel="noopener noreferrer"&gt;coverlet&lt;/a&gt; and you can add it as a nuget package to your test project: &lt;code&gt;dotnet add package coverlet.msbuild&lt;/code&gt;. To use its functionality, we need to add a few additional parameters to the &lt;code&gt;Test&lt;/code&gt; task.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;DotNetCoreTestSettings&lt;/span&gt;
     &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="n"&gt;ArgumentCustomization&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/p:CollectCoverage=true"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                                             &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/p:CoverletOutputFormat=opencover"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                                             &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/p:ThresholdType=line"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                                             &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"/p:Threshold=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;coverageThreshold&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
     &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="nf"&gt;DotNetCoreTest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"./Test/Test.csproj"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What it does is add those parameters to MSBuild, which will then use coverlet to calculate the coverage. We want to have line coverage, which we can specify using &lt;code&gt;/p:ThresholdType=line&lt;/code&gt;. This will calculate the percentage depending on whether or not every relevant line is covered by a unit test. If the percentage drops below a certain threshold (defined op top of &lt;code&gt;build.cake&lt;/code&gt;), it will fail the build. The output format is opencover which we need to export the result to &lt;a href="https://coveralls.io/" rel="noopener noreferrer"&gt;Coveralls.io&lt;/a&gt;, where we can keep track of our coverage cross build and cross branch. The advantage of using an external service is that you can't simply adjust the threshold to fix a build failure. It will also hold you back to merge changes to master in case of a drop in coverage (thresholds can be agile about this) when configured that way in GitHub for example.&lt;/p&gt;

&lt;p&gt;To upload the changes to Coveralls.io we need three extra dependencies.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="n"&gt;tool&lt;/span&gt; &lt;span class="s"&gt;"nuget:https://www.nuget.org/api/v2?package=coveralls.io&amp;amp;version=1.4.2"&lt;/span&gt;
&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="n"&gt;addin&lt;/span&gt; &lt;span class="s"&gt;"nuget:https://www.nuget.org/api/v2?package=Cake.Coveralls&amp;amp;version=0.8.0"&lt;/span&gt;
&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="n"&gt;addin&lt;/span&gt; &lt;span class="s"&gt;"nuget:https://www.nuget.org/api/v2?package=Cake.Incubator&amp;amp;version=2.0.1"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://cakebuild.net/api/Cake.Incubator/EnvironmentExtensions/31E6B762" rel="noopener noreferrer"&gt;Incubator&lt;/a&gt; is needed to work with environment variables as &lt;strong&gt;we don't want to include our Coveralls.io API token in the build script&lt;/strong&gt; (seriously, don't). No matter the CI tool, you can always add environment variables to use in your build logic. The proper way is to have them in the build script as encrypted variables, so that they can't be used other than during the CI phases, but you can still adjust them via source control. I'm using &lt;a href="https://www.appveyor.com/" rel="noopener noreferrer"&gt;Appveyor&lt;/a&gt; myself and it can &lt;a href="https://ci.appveyor.com/tools/encrypt" rel="noopener noreferrer"&gt;encrypt variables&lt;/a&gt; to add to your &lt;code&gt;appveyor.yml&lt;/code&gt; script.&lt;/p&gt;

&lt;p&gt;To upload the coverage statistics via Cake, we make use of the &lt;a href="https://cakebuild.net/addins/code-coverage/#cake-coveralls" rel="noopener noreferrer"&gt;Coveralls&lt;/a&gt; add-on. Combine this with incubator to retrieve the API token during build and we can upload the file generated by coverlet.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="nf"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Upload-Coverage"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Does&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;isRunningOnAppveyor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;EnvironmentVariable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;"APPVEYOR"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;isRunningOnAppveyor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nf"&gt;Information&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Running on Appveyor, uploading coverage information to coveralls.io"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;CoverallsIo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"./Test/coverage.xml"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;CoverallsIoSettings&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;RepoToken&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;EnvironmentVariable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"coveralls_token"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that we've got all of this available, we can define a basic CI task to execute on the build machine.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="nf"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"CI"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Build the code, test and validate"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsDependentOn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Build"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsDependentOn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Test"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsDependentOn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Validate"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsDependentOn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Upload-Coverage"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As we're entering a world where C# has the ability to run on other machines than Windows alone, I made a Unix specific build task too.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="nf"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"CI-UNIX"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Build the code, test and validate"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsDependentOn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Build"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsDependentOn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Test"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This way we have Appveyor to run the tests on Windows (including the static analysis and code coverage uploading) and Linux, and &lt;a href="https://travis-ci.org" rel="noopener noreferrer"&gt;Travis.ci&lt;/a&gt; to run the tests on OSX. As we've got a Cake build script, all we need is the two config files to tell our CI instances what to do. Beware, Appveyor can run PowerShell on Windows and Linux, so we need to check where we are before executing the same command twice.&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;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Visual Studio &lt;/span&gt;&lt;span class="m"&gt;2017&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Ubuntu&lt;/span&gt;
&lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;coveralls_token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;secure&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;HMJLoYbkSD1p35JnHiBjv02frHKMvasoD9J6wLnzjSUsdPwFwiHU8t0SwcvyAYi1&lt;/span&gt;
&lt;span class="na"&gt;build_script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;pwsh&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;if ($isWindows) {&lt;/span&gt;
        &lt;span class="s"&gt;.\build.ps1 -Target CI&lt;/span&gt;
      &lt;span class="s"&gt;}&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;sh&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./build.sh --target=CI-UNIX&lt;/span&gt;

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

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;csharp&lt;/span&gt;
&lt;span class="na"&gt;mono&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;latest&lt;/span&gt;
&lt;span class="na"&gt;dotnet&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;2.1.200&lt;/span&gt;
&lt;span class="na"&gt;os&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;osx&lt;/span&gt;
&lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./build.sh --target=CI-UNIX&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;If you're curious about the output or build time, you can have a look at the project on &lt;a href="https://ci.appveyor.com/project/JanJoris/dotnet-core-sample" rel="noopener noreferrer"&gt;Appveyor's&lt;/a&gt; or &lt;a href="https://travis-ci.org/JanDeDobbeleer/dotnet-core-sample" rel="noopener noreferrer"&gt;Travis'&lt;/a&gt; website.&lt;/p&gt;

&lt;p&gt;This is as far as I wanted to go with this. I'll try to keep the project up-to-date with interesting add-ons, or maybe you know of some improvement and would like to propose a PR? Do not hesitate to get in touch!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/JanDeDobbeleer/dotnet-core-sample" rel="noopener noreferrer"&gt;Source Code&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Originally posted at: &lt;a href="https://blog.itdepends.be/dotnet-core-cake/" rel="noopener noreferrer"&gt;https://blog.itdepends.be/dotnet-core-cake/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>productivity</category>
      <category>tutorial</category>
      <category>devops</category>
    </item>
    <item>
      <title>Intercept HTTP traffic exiting a docker container</title>
      <dc:creator>Jan De Dobbeleer</dc:creator>
      <pubDate>Thu, 29 Mar 2018 20:27:16 +0000</pubDate>
      <link>https://dev.to/jandedobbeleer/intercept-http-traffic-exiting-a-docker-container-3g68</link>
      <guid>https://dev.to/jandedobbeleer/intercept-http-traffic-exiting-a-docker-container-3g68</guid>
      <description>&lt;p&gt;Imagine the following problem. You are working on an application running inside a docker container and you feel the need to inspect the http requests being executed by your application. Coming from an app development background myself, it can be a huge benefit to use proxy tooling like &lt;a href="https://mitmproxy.org/" rel="noopener noreferrer"&gt;mitmproxy&lt;/a&gt; to see the actual request being made instead of staying stuck trying to figure out what's wrong. Or, use the proxy to alter requests and easily test use cases or reproduce bug reports. All in all, there's a significant gain in lead time when using the right tool for the job. Otherwise &lt;strong&gt;we'd still be adding print statements everywhere&lt;/strong&gt; just for the sake of debugging (I know you're doing it).&lt;/p&gt;

&lt;p&gt;In this case, I have a Python Django web app running in a Debian Jessie container and I needed to see the flow of requests being made towards the backend REST API. Installing mitmproxy is a breeze, as it's a cross platform tool, you can follow the installation guide for your platform. I'm running it using the WSL on Windows myself (Ubuntu). Before doing anything else, start mitmproxy and get comfortable. The default port for capturing traffic is 8080, change it using the &lt;code&gt;-p &amp;lt;portnumber&amp;gt;&lt;/code&gt; option in case conflicts would occur.&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="nv"&gt;$ &lt;/span&gt;mitmproxy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Docker provides proxy support out of the box which is convenient.&lt;br&gt;
As we've got mitmproxy running on our host machine, we want to route all traffic exiting the container to that once. To do so, I created a new docker-compose.override file which holds all settings and (almost all) logic.&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;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;2'&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;mv-web&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;HTTP_PROXY=mitmproxy:8080&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;HTTPS_PROXY=mitmproxy:8080&lt;/span&gt;
    &lt;span class="na"&gt;extra_hosts&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;mitmproxy:10.125.2.187"&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sh -c 'python3 certificate.py &amp;amp;&amp;amp; python3 manage.py runserver 0.0.0.0:8020'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above example I only added the settings relevant to illustrate the solution. You can see two environment variables, &lt;code&gt;HTTP_PROXY&lt;/code&gt; and &lt;code&gt;HTTPS_PROXY&lt;/code&gt;. These tell the container to route all exiting traffic towards mitmproxy, who's added as an extra host. The ip address &lt;code&gt;10.125.2.187&lt;/code&gt; is the one of my host machine, change it to whatever yours is.&lt;/p&gt;

&lt;p&gt;Now, you might notice there's another little item in there called &lt;code&gt;python3 certificate.py&lt;/code&gt; which runs just before we start the Django app. If you'd only use the proxy settings, http requests would enter mitmproxy just fine, but https requests will not show up. The reason is that mitmproxy uses it's own certificate to be able to decrypt the traffic flowing through. As a result, the requests will get blocked as the OS doesn't trust that certificate (like it should).&lt;/p&gt;

&lt;p&gt;Initially I tried to add the certificate to the container's OS trusted certificate store, but that didn't work out as planned. I could run a &lt;code&gt;curl&lt;/code&gt; command inside the container to an https endpoint and &lt;strong&gt;it flowed through mitmproxy like a boss&lt;/strong&gt;, but when I started the Django app, https requests kept being aborted. It took me a while to figure out what was going on. Our Django app uses the &lt;a href="http://docs.python-requests.org/en/master/" rel="noopener noreferrer"&gt;Requests&lt;/a&gt; library to execute http calls. This one in turn uses &lt;a href="https://github.com/certifi/python-certifi" rel="noopener noreferrer"&gt;certifi&lt;/a&gt; to create its trusted certificate store, which didn't have a copy of mitmproxy's root certificate causing all https calls being silenced and not exiting the container.&lt;/p&gt;

&lt;p&gt;The solution, once you know it, is straightforward. Add a script called &lt;code&gt;certificate.py&lt;/code&gt; to your container (either by volume mapping, or as a build step) together with mitmproxy's root certificate (located at &lt;code&gt;~/.mitmproxy/mitmproxy-ca-cert.pem&lt;/code&gt;) and edit the &lt;code&gt;docker-compose.override.yml&lt;/code&gt; file to execute &lt;code&gt;certificate.py&lt;/code&gt; before starting the Django app.&lt;/p&gt;

&lt;p&gt;Copy mitmproxy's root certificate to your Django app's root folder:&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="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cp&lt;/span&gt; ~/.mitmproxy/mitmproxy-ca-cert.pem &amp;lt;project root&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a new file called &lt;code&gt;certificate.py&lt;/code&gt; in the same project root:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;certifi&lt;/span&gt;

&lt;span class="n"&gt;caroot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;certifi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;mitmproxy-ca-cert.pem&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;rb&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;mitm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;cert&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mitm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;caroot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ab&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cert&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;w00t, added mitmproxy root cert to certifi!&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, when you up the docker container with compose, you'll see all traffic flowing through mitmproxy! Happy debugging!&lt;/p&gt;

&lt;h2&gt;
  
  
  Small additions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Multiple docker-compose files
&lt;/h3&gt;

&lt;p&gt;When using a &lt;code&gt;docker-compose.override.yml&lt;/code&gt; file and you've already specified another non-standard &lt;code&gt;docker-compose&lt;/code&gt; file, make sure to use &lt;code&gt;-f&lt;/code&gt; twice to load both (or more) settings files. So, imagine your settings file is called &lt;code&gt;docker-compose.standalone.yml&lt;/code&gt; and you've added all files following this tutorial, the command to up your container becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker-compose &lt;span class="nt"&gt;-f&lt;/span&gt; .&lt;span class="se"&gt;\d&lt;/span&gt;ocker-compose.standalone.yml &lt;span class="nt"&gt;-f&lt;/span&gt; .&lt;span class="se"&gt;\d&lt;/span&gt;ocker-compose.override.yml up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our override file should be last so that no setting can be overwritten by settings in previous files, The last in wins.&lt;/p&gt;

&lt;h3&gt;
  
  
  Check firewall settings
&lt;/h3&gt;

&lt;p&gt;As I'm running this on Windows, I still had to open up port &lt;code&gt;8080&lt;/code&gt; to allow the container to connect to mitmproxy. Double check on whatever system you're using that this isn't the thing causing a headache before proceeding 😑.&lt;/p&gt;

&lt;h3&gt;
  
  
  But I'm not using Python or Requests
&lt;/h3&gt;

&lt;p&gt;In case you want to do this but don't have a Python app using Requests, you can try to add the certificate to the container's OS as I mentioned before. For some reason, I also had to set it on every container start, but that's not too much hassle. Instead of &lt;code&gt;certificate.py&lt;/code&gt;, create a file called &lt;code&gt;certificate.sh&lt;/code&gt; with the following content:&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;mkdir&lt;/span&gt; /usr/local/share/ca-certificates/extra
&lt;span class="nb"&gt;cp &lt;/span&gt;mitmproxy-ca-cert.pem /usr/local/share/ca-certificates/extra/root.cert.crt
update-ca-certificates
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, change the &lt;code&gt;docker-compose.override.yml&lt;/code&gt; file to execute this one instead of &lt;code&gt;certificate.py&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sh -c './certificate.sh &amp;amp;&amp;amp; &amp;lt;whatever the command&amp;gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The example assumes a Debian based container, make sure to alter &lt;code&gt;certificate.sh&lt;/code&gt; to add the root certificate to the correct location according to your container's OS.&lt;/p&gt;

&lt;p&gt;Have fun!&lt;/p&gt;

</description>
      <category>docker</category>
      <category>mitmproxy</category>
      <category>https</category>
      <category>ssl</category>
    </item>
    <item>
      <title>Hi, I'm Jan De Dobbeleer</title>
      <dc:creator>Jan De Dobbeleer</dc:creator>
      <pubDate>Sat, 01 Apr 2017 12:41:39 +0000</pubDate>
      <link>https://dev.to/jandedobbeleer/hi-im-jan-de-dobbeleer</link>
      <guid>https://dev.to/jandedobbeleer/hi-im-jan-de-dobbeleer</guid>
      <description>&lt;p&gt;I have been coding for 4 years.&lt;/p&gt;

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

&lt;p&gt;I live in Diest, Belgium.&lt;/p&gt;

&lt;p&gt;I work for Unleashed&lt;/p&gt;

&lt;p&gt;I mostly program in these languages: PowerShell, Python, C#, Ruby, Java, Javascript.&lt;/p&gt;

&lt;p&gt;I am currently learning more about everything.&lt;/p&gt;

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

</description>
      <category>introduction</category>
    </item>
  </channel>
</rss>
