<?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: Quinn Zhu</title>
    <description>The latest articles on DEV Community by Quinn Zhu (@gitgo_5662).</description>
    <link>https://dev.to/gitgo_5662</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4064033%2F3b8164f8-c06e-456b-a431-d2555ccc9ea9.png</url>
      <title>DEV Community: Quinn Zhu</title>
      <link>https://dev.to/gitgo_5662</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/gitgo_5662"/>
    <language>en</language>
    <item>
      <title>Your First Hour in a New Repo: Build a Reading Order from Git History</title>
      <dc:creator>Quinn Zhu</dc:creator>
      <pubDate>Thu, 15 Oct 2026 11:29:37 +0000</pubDate>
      <link>https://dev.to/gitgo_5662/your-first-hour-in-a-new-repo-build-a-reading-order-from-git-history-4l5j</link>
      <guid>https://dev.to/gitgo_5662/your-first-hour-in-a-new-repo-build-a-reading-order-from-git-history-4l5j</guid>
      <description>&lt;h2&gt;
  
  
  Conclusion first: do not read a new repo alphabetically
&lt;/h2&gt;

&lt;p&gt;You join a repo on Monday. Nobody has time to walk you through it. So you open the file tree and start at the top.&lt;/p&gt;

&lt;p&gt;That is the slowest path through a codebase. Files that change together belong together. Git already recorded which files move as one unit.&lt;/p&gt;

&lt;p&gt;Read the coupled files first and the architecture appears faster. This workflow has three steps: extract co-change pairs, expand them into a reading order, then use an agent to cover what you cannot read in time. Setup costs about fifteen minutes.&lt;/p&gt;

&lt;p&gt;The scripts below are templates. Run them in your own clone and treat the ranking as a hypothesis to verify.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1 — Extract co-change pairs from commit history
&lt;/h2&gt;

&lt;p&gt;A commit that touches &lt;code&gt;checkout.ts&lt;/code&gt; and &lt;code&gt;cart.ts&lt;/code&gt; is evidence of a relationship. Repeat that across a year of history and the strong edges stand out from the noise.&lt;/p&gt;

&lt;p&gt;Limit the window to 12–18 months. Older commits describe code that no longer exists.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Dump one commit per NUL byte, followed by the file names it touched.&lt;/span&gt;
git log &lt;span class="nt"&gt;--no-merges&lt;/span&gt; &lt;span class="nt"&gt;--since&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"18 months ago"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--pretty&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;format:&lt;span class="s1"&gt;'%x00'&lt;/span&gt; &lt;span class="nt"&gt;--name-only&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /tmp/cochange.log

&lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt; /tmp/cochange.log   &lt;span class="c"&gt;# sanity check: is this file absurdly large?&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now count the pairs.&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="c1"&gt;# cochange.py — rank file pairs by how often they change together
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;collections&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;itertools&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;

&lt;span class="n"&gt;IGNORE&lt;/span&gt; &lt;span class="o"&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;vendor/&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;node_modules/&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;dist/&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;third_party/&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;.lock&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;raw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&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;git&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;log&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;--no-merges&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;--since=18 months ago&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;--pretty=format:%x00&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;--name-only&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;capture_output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;check&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;

&lt;span class="n"&gt;pairs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;collections&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;touched&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;collections&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;chunk&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\x00&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;files&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;splitlines&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;
    &lt;span class="n"&gt;files&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;files&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IGNORE&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;files&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;continue&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;files&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;touched&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;itertools&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;combinations&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;files&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;pairs&lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

&lt;span class="nf"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;pairs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;most_common&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;  &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;  &amp;lt;-&amp;gt;  &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="si"&gt;}&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;Check two things before you trust the output. First, generated files and lockfiles dominate raw counts, so keep the ignore list honest. Second, squash-merged history turns every commit into a whole feature, which flattens the pair counts.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;--no-merges&lt;/code&gt; flag hides merge commits. That is usually what you want. If your team merges feature branches without squashing, drop the flag and compare the two outputs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2 — Expand one seed into a reading order
&lt;/h2&gt;

&lt;p&gt;The top pair is a starting point, not a plan. Expand outward from the most frequently touched file and stop after roughly a dozen files.&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="c1"&gt;# Continue in the same script: walk the coupling graph.
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;collections&lt;/span&gt;

&lt;span class="n"&gt;neighbors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;collections&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;defaultdict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;collections&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;pairs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;neighbors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;
    &lt;span class="n"&gt;neighbors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;

&lt;span class="n"&gt;seed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;touched&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;most_common&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;seen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;best&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;recent&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:]:&lt;/span&gt;            &lt;span class="c1"&gt;# weight the last few picks
&lt;/span&gt;        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;cand&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;neighbors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;recent&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cand&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;seen&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;score&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;best&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cand&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;best&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt;
    &lt;span class="n"&gt;order&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="n"&gt;best&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;seen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;best&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="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;reading order:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;. &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&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;Greedy expansion is a heuristic. It can wander into a test-only cluster and stall there. If the list looks wrong, change the seed to a file you already know matters.&lt;/p&gt;

&lt;p&gt;Then write the plan down with a stop condition for each block.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Time&lt;/th&gt;
&lt;th&gt;Target&lt;/th&gt;
&lt;th&gt;Stop when&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0:00–0:20&lt;/td&gt;
&lt;td&gt;top 3 coupled files&lt;/td&gt;
&lt;td&gt;you can name the entry point and its caller&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0:20–1:00&lt;/td&gt;
&lt;td&gt;full pair list&lt;/td&gt;
&lt;td&gt;you can draw five arrows between modules&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1:00–2:00&lt;/td&gt;
&lt;td&gt;one end-to-end test&lt;/td&gt;
&lt;td&gt;the test passes locally and you know what it asserts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2:00–3:00&lt;/td&gt;
&lt;td&gt;agent summaries of the rest&lt;/td&gt;
&lt;td&gt;every claim is checked against code or a test&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The third row matters most. A reading order you cannot run is still a guess.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3 — Use an agent for the files you cannot reach
&lt;/h2&gt;

&lt;p&gt;You will not read 200 files on day one. Hand the ranked list to a coding agent and ask for narrow, checkable answers.&lt;/p&gt;

&lt;p&gt;MonkeyCode offers free model access and a free server option, which makes this step cheap to try from a work laptop. Disclosure: This article was prepared as part of MonkeyCode's product outreach.&lt;/p&gt;

&lt;p&gt;Keep the prompt narrow. Broad questions produce broad guesses.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;For each file listed below, answer in at most four lines:
1. Which files in this repo reference it? Give file:line, or "not found".
2. What does it return or mutate?
3. Which test exercises it? Give the test name, or "no test found".
4. What would break if this file were deleted?

Files:
&amp;lt;paste the reading order here&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;"Not found" and "no test found" are the most useful answers. They mark the edges of the repo's documented behavior.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4 — Verify before you believe
&lt;/h2&gt;

&lt;p&gt;Agent output is a hypothesis, not a fact. Three commands settle most of it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Does the caller really exist?&lt;/span&gt;
&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-rn&lt;/span&gt; &lt;span class="s2"&gt;"parseCheckout"&lt;/span&gt; &lt;span class="nt"&gt;--include&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"*.ts"&lt;/span&gt; src/ | &lt;span class="nb"&gt;head&lt;/span&gt;

&lt;span class="c"&gt;# Is this file actually alive?&lt;/span&gt;
git log &lt;span class="nt"&gt;-1&lt;/span&gt; &lt;span class="nt"&gt;--format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'%h %ad %an'&lt;/span&gt; &lt;span class="nt"&gt;--date&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;short &lt;span class="nt"&gt;--&lt;/span&gt; src/cart.ts

&lt;span class="c"&gt;# Does the claimed test exist, and does it pass?&lt;/span&gt;
npm &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nt"&gt;--testPathPattern&lt;/span&gt; cart
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the grep finds nothing, the agent invented the caller. If the last commit is four years old, the file is probably dead code, not core logic.&lt;/p&gt;

&lt;p&gt;Record each verified fact in one note file. That note becomes the onboarding document for the next hire, which is a better gift than a Slack summary.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your first PR comes from the gaps
&lt;/h2&gt;

&lt;p&gt;The "no test found" list is your backlog. Pick one small function and add the missing test. It is a real contribution, it is low risk, and it forces you to run the code.&lt;/p&gt;

&lt;p&gt;Do not refactor anything in week one. You do not yet know which odd-looking code is load-bearing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limitations and who should skip this
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Repos under about 40 files: just read them all in one sitting.&lt;/li&gt;
&lt;li&gt;Squash-merge-only history: co-change counts flatten, so pair ranking gets weak.&lt;/li&gt;
&lt;li&gt;Heavy vendoring or generated code: your ignore list does most of the work.&lt;/li&gt;
&lt;li&gt;Teams without a working local test command: verify by reading code instead.&lt;/li&gt;
&lt;li&gt;Anyone who cannot review agent output critically: skip Step 3 entirely.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Do not hand security-critical paths to an agent on day one. Read those yourself, slowly.&lt;/p&gt;

&lt;p&gt;The pair list also says nothing about runtime behavior. Two files can co-change because a formatter touches them together, not because they are coupled. Skim the commit messages for the top pairs before you build a mental model on them.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to do next
&lt;/h2&gt;

&lt;p&gt;Run Step 1 on the repo you joined this week. Paste the top ten pairs into your notes. You now have a reading order, a verification habit, and a first PR candidate.&lt;/p&gt;

&lt;p&gt;If your laptop cannot spare the cycles for Step 3, MonkeyCode's free server option is one way to move that work off your machine.&lt;/p&gt;

</description>
      <category>git</category>
      <category>onboarding</category>
      <category>ai</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Scan the Diff Before You Request Agent Review</title>
      <dc:creator>Quinn Zhu</dc:creator>
      <pubDate>Tue, 13 Oct 2026 02:28:31 +0000</pubDate>
      <link>https://dev.to/gitgo_5662/scan-the-diff-before-you-request-agent-review-2j17</link>
      <guid>https://dev.to/gitgo_5662/scan-the-diff-before-you-request-agent-review-2j17</guid>
      <description>&lt;p&gt;Do not request review on an agent patch yet.&lt;br&gt;
A leaked secret outlives a bad function name.&lt;br&gt;
Scan the diff, then write a replay note.&lt;/p&gt;
&lt;h2&gt;
  
  
  Start from the review gate
&lt;/h2&gt;

&lt;p&gt;You are the new engineer on this repo.&lt;br&gt;
Your first pull request should stay very small.&lt;br&gt;
An agent may draft the patch for you.&lt;/p&gt;

&lt;p&gt;You still decide what reviewers are allowed to see.&lt;br&gt;
Treat the agent summary as an unverified claim.&lt;br&gt;
Every claim needs a command you can rerun.&lt;/p&gt;

&lt;p&gt;A confident paragraph is not evidence at all.&lt;br&gt;
You need a command log beside that paragraph.&lt;br&gt;
Git output beats a polished explanation every time.&lt;/p&gt;
&lt;h2&gt;
  
  
  Keep this hour narrow
&lt;/h2&gt;

&lt;p&gt;Change only one behavior during this first hour.&lt;br&gt;
Touch only the files that this behavior needs.&lt;br&gt;
Leave lockfiles and migrations alone unless the ticket names them.&lt;/p&gt;

&lt;p&gt;Do not explore the whole tree on this branch.&lt;br&gt;
Do not ask the agent to clean unrelated files.&lt;br&gt;
Wide diffs hide secrets and unrelated edits together.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 1: Freeze the base ref
&lt;/h2&gt;

&lt;p&gt;Pick the base branch that reviewers already trust.&lt;br&gt;
Write that ref down before you edit anything.&lt;br&gt;
Do not guess the base ref from memory later.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git fetch origin
git rev-parse &lt;span class="nt"&gt;--abbrev-ref&lt;/span&gt; HEAD
git merge-base HEAD origin/main
git status &lt;span class="nt"&gt;--short&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Stop if your working tree is not clean.&lt;br&gt;
Stop if the base ref is missing locally.&lt;br&gt;
A dirty tree makes this scan meaningless now.&lt;/p&gt;

&lt;p&gt;Replace origin/main if your default branch name differs.&lt;br&gt;
Ask a teammate for the real base name.&lt;br&gt;
Do not invent a base just to pass.&lt;/p&gt;

&lt;p&gt;The three-dot diff starts at the merge base.&lt;br&gt;
It shows changes your branch introduced, not upstream noise.&lt;br&gt;
A two-dot diff can blame files you never edited.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 2: Keep secrets out of the prompt
&lt;/h2&gt;

&lt;p&gt;Never paste env file contents into a chat.&lt;br&gt;
Never paste private keys, tokens, or customer rows.&lt;br&gt;
Name the file path when the agent must avoid it.&lt;/p&gt;

&lt;p&gt;Say which files the agent is allowed to touch.&lt;br&gt;
Say which commands the agent is allowed to run.&lt;br&gt;
Say that unknown files must stay completely untouched.&lt;/p&gt;

&lt;p&gt;A free model does not make a secret safer.&lt;br&gt;
The secret already left your machine in that paste.&lt;br&gt;
Treat every prompt as a copy you may not recall.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 3: Run a diff scan before review
&lt;/h2&gt;

&lt;p&gt;This script is only a proposal for you.&lt;br&gt;
It is an unexecuted example for your branch.&lt;br&gt;
Adapt the base ref and path rules first.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class="c"&gt;# Unexecuted example. Review it before you run it.&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail

&lt;span class="nv"&gt;base&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;/main&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; git rev-parse &lt;span class="nt"&gt;--verify&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$base&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;/dev/null 2&amp;gt;&amp;amp;1&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"FAIL: base ref not found"&lt;/span&gt;
  &lt;span class="nb"&gt;exit &lt;/span&gt;2
&lt;span class="k"&gt;fi

&lt;/span&gt;&lt;span class="nv"&gt;files&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;git diff &lt;span class="nt"&gt;--name-only&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;base&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;...HEAD"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-z&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$files&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"FAIL: empty diff against &lt;/span&gt;&lt;span class="nv"&gt;$base&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nb"&gt;exit &lt;/span&gt;2
&lt;span class="k"&gt;fi

&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"FILES:"&lt;/span&gt;
&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'%s\n'&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$files&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="nv"&gt;blocked&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'(^|/)(\.env|\.env\..*|id_rsa|id_ed25519|.*\.pem|.*\.p12|.*\.key|credentials\.json|secrets\.ya?ml)$'&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'%s\n'&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$files&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$blocked&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"FAIL: sensitive path in diff"&lt;/span&gt;
  &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi

&lt;/span&gt;&lt;span class="nv"&gt;pattern&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'AKIA[0-9A-Z]{16}|-----BEGIN [A-Z ]*PRIVATE KEY-----|ghp_[A-Za-z0-9]{20,}|xox[baprs]-[A-Za-z0-9-]{10,}'&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;git diff &lt;span class="nt"&gt;--unified&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0 &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;base&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;...HEAD"&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="nt"&gt;-q&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$pattern&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"FAIL: possible secret text in diff"&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Do not print the match in a shared log."&lt;/span&gt;
  &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi

&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"PASS: no blocked path or obvious token pattern"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save the script outside the repository if possible.&lt;br&gt;
Run it with the base ref as its argument.&lt;br&gt;
Read each failure before you silence the script.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bash scan-first-diff.sh origin/main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A pass is not a full security audit.&lt;br&gt;
It catches obvious paths and a few token shapes.&lt;br&gt;
Your team scanner still matters when you have one.&lt;/p&gt;

&lt;p&gt;The failure path can still reveal a secret nearby.&lt;br&gt;
Run the scan in a private terminal, not a shared log.&lt;br&gt;
If a real secret appears, rotate it with the owner.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 4: Use a decision table
&lt;/h2&gt;

&lt;p&gt;Read this table before you push the branch.&lt;br&gt;
Act on the row that you actually hit.&lt;br&gt;
Do not blur two rows into a maybe.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scan result&lt;/th&gt;
&lt;th&gt;What you do&lt;/th&gt;
&lt;th&gt;What you do not do&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Sensitive path listed&lt;/td&gt;
&lt;td&gt;Remove that file from the branch&lt;/td&gt;
&lt;td&gt;Ask the model to ignore it in prose&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Token-like text in the diff&lt;/td&gt;
&lt;td&gt;Tell the credential owner and rotate&lt;/td&gt;
&lt;td&gt;Hide the line and hope review misses it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Empty diff&lt;/td&gt;
&lt;td&gt;Stop and restate the one behavior&lt;/td&gt;
&lt;td&gt;Open review only to show effort&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pass, but a hunk is unexplained&lt;/td&gt;
&lt;td&gt;Drop that hunk or ask a human&lt;/td&gt;
&lt;td&gt;Ship the model explanation as your own&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pass, and you can replay the test&lt;/td&gt;
&lt;td&gt;Write the replay note next&lt;/td&gt;
&lt;td&gt;Add extra files for completeness&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A shared branch needs a teammate before any rewrite.&lt;br&gt;
This table does not teach you to force-push.&lt;br&gt;
Ask the owner before you rewrite any public history.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 5: Fix a failure without hiding it
&lt;/h2&gt;

&lt;p&gt;Do not delete the failing line from the log.&lt;br&gt;
Copy the flagged path, then remove it from the branch.&lt;br&gt;
Commit that removal before you rerun the scan.&lt;/p&gt;

&lt;p&gt;If the file is new, delete it from the branch.&lt;br&gt;
If the file is tracked, restore the base version with help.&lt;br&gt;
Do not hide a flagged path inside gitignore.&lt;/p&gt;

&lt;p&gt;Rerun the same script after that fix lands.&lt;br&gt;
A second pass still needs the replay note.&lt;br&gt;
Do not request review from a failing log.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 6: Write the replay note
&lt;/h2&gt;

&lt;p&gt;Put this note in the pull request body.&lt;br&gt;
A reviewer should rerun your checks without guessing.&lt;br&gt;
Keep each line short enough to verify quickly.&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="gu"&gt;## Replay note&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; Base ref: origin/main
&lt;span class="p"&gt;-&lt;/span&gt; Branch: your-branch-name
&lt;span class="p"&gt;-&lt;/span&gt; One behavior: one sentence you can defend
&lt;span class="p"&gt;-&lt;/span&gt; Allowed paths: list only those paths
&lt;span class="p"&gt;-&lt;/span&gt; Command run: the exact test command
&lt;span class="p"&gt;-&lt;/span&gt; Scan result: pass or fail, plus script name
&lt;span class="p"&gt;-&lt;/span&gt; Not run: anything you skipped on purpose
&lt;span class="p"&gt;-&lt;/span&gt; Model claim you rejected: one sentence, or none
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fill every line using your own words only.&lt;br&gt;
Do not paste an agent summary over those lines.&lt;br&gt;
If any line is unknown, the review is early.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 7: Use a remote run only as a tool
&lt;/h2&gt;

&lt;p&gt;Disclosure: This article was prepared as part of MonkeyCode's product outreach.&lt;/p&gt;

&lt;p&gt;MonkeyCode offers free model access and a free server option.&lt;br&gt;
Both are availability claims supplied for this article, not measured results.&lt;br&gt;
Current quotas, hardware, and time limits are not stated.&lt;/p&gt;

&lt;p&gt;Check the current product docs before you rely on either.&lt;br&gt;
Those offers can change, and this article will not track them.&lt;br&gt;
Do not plan a deadline around an unverified limit.&lt;/p&gt;

&lt;p&gt;Use the free model to draft replay note wording.&lt;br&gt;
You still type the commands and read the output.&lt;br&gt;
Use a free server only when your team allows that workspace.&lt;/p&gt;

&lt;p&gt;Do not upload secrets so a remote scan looks better.&lt;br&gt;
The scan should see the diff, not your password store.&lt;br&gt;
If that workspace is unclear, run the script locally.&lt;/p&gt;

&lt;p&gt;Read the current MonkeyCode docs before any remote run.&lt;br&gt;
Try the scan on a branch you can delete.&lt;br&gt;
Stop if the docs disagree with this article.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 8: Reject a yes from the model
&lt;/h2&gt;

&lt;p&gt;Ask the agent which checks it actually skipped.&lt;br&gt;
A short approval line is not a real scan.&lt;br&gt;
Compare its file list with git diff output.&lt;/p&gt;

&lt;p&gt;If those lists differ, believe git every time.&lt;br&gt;
If the agent reports no secrets, rerun the script.&lt;br&gt;
If you cannot explain a line, drop that line.&lt;/p&gt;

&lt;p&gt;This is the habit you want on later reviews.&lt;br&gt;
Your first review is where that habit starts.&lt;br&gt;
Reviewers teach faster when your note stays honest.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who should skip this workflow
&lt;/h2&gt;

&lt;p&gt;Skip this if CI already blocks secret paths.&lt;br&gt;
Follow that gate instead of a second unofficial script.&lt;br&gt;
Skip this if you cannot open pull requests yet.&lt;/p&gt;

&lt;p&gt;Skip this flow during an active production incident.&lt;br&gt;
Incident work needs the on-call owner, not a first-hour test.&lt;br&gt;
Skip this if the ticket requires production credentials.&lt;/p&gt;

&lt;p&gt;That ticket needs a human owner, not an agent run.&lt;br&gt;
You are still learning the review path on purpose.&lt;br&gt;
An incident is the wrong classroom for this script.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limits you should say out loud
&lt;/h2&gt;

&lt;p&gt;The pattern list misses many private token formats.&lt;br&gt;
It misses secrets that are split across lines.&lt;br&gt;
It misses tokens that do not match these shapes.&lt;/p&gt;

&lt;p&gt;The path list misses custom secret file names.&lt;br&gt;
Add the secret names your repository actually uses.&lt;br&gt;
Do not delete a team rule to match this example.&lt;/p&gt;

&lt;p&gt;The script does not rotate any credential for you.&lt;br&gt;
The script does not prove that your test passed.&lt;br&gt;
The script does not make the agent accountable.&lt;/p&gt;

&lt;p&gt;This example was not run against your repository.&lt;br&gt;
Treat the listing as a starting point only.&lt;br&gt;
Change it until a teammate accepts the blocked paths.&lt;/p&gt;

&lt;h2&gt;
  
  
  Before you request review
&lt;/h2&gt;

&lt;p&gt;Run the scan and keep the last lines.&lt;br&gt;
Paste the replay note in your own words.&lt;br&gt;
Read the full diff with the agent closed.&lt;/p&gt;

&lt;p&gt;Request review only when all three answers hold.&lt;br&gt;
You can name the base ref from the command output.&lt;br&gt;
You can name the exact test command you ran.&lt;/p&gt;

&lt;p&gt;You can name every file you would defend.&lt;br&gt;
If one answer fails, keep the branch in draft.&lt;br&gt;
Fix that gap, or close the branch and start smaller.&lt;/p&gt;

&lt;p&gt;A delayed first review is cheaper than a leaked key.&lt;br&gt;
Leave the draft closed until those answers are easy.&lt;br&gt;
Your name is on the pull request, not the model's.&lt;/p&gt;

</description>
      <category>git</category>
      <category>beginners</category>
      <category>security</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Score Every Hunk Before Your First Agent PR</title>
      <dc:creator>Quinn Zhu</dc:creator>
      <pubDate>Sun, 11 Oct 2026 21:57:16 +0000</pubDate>
      <link>https://dev.to/gitgo_5662/score-every-hunk-before-your-first-agent-pr-i6l</link>
      <guid>https://dev.to/gitgo_5662/score-every-hunk-before-your-first-agent-pr-i6l</guid>
      <description>&lt;p&gt;You should not open your first agent pull request blind. Score every changed hunk before you request human review. A fluent model reply is not evidence of safety.&lt;/p&gt;

&lt;p&gt;You joined this repo as a junior during hour one. You still lack a map of risky paths. An agent can still draft a wide patch quickly.&lt;/p&gt;

&lt;p&gt;This hour is for a gate, not for a demo. You will build a packet you can defend. You will refuse the pull request when a score fails.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hold the boundary first
&lt;/h2&gt;

&lt;p&gt;Keep the agent run off your real pull request branch. Bring back a diff, a test note, and a revert line. Leave secrets, tokens, and production configs out of the prompt.&lt;/p&gt;

&lt;p&gt;Do not allow edits under CI workflows during this pass. Do not allow lockfile edits or migration files either. Those paths need a senior review, not a first hour guess.&lt;/p&gt;

&lt;h2&gt;
  
  
  Name the tool without inflating it
&lt;/h2&gt;

&lt;p&gt;Disclosure: This article was prepared as part of MonkeyCode's product outreach.&lt;/p&gt;

&lt;p&gt;MonkeyCode enters here as one place to run that first pass. The operator supplied two availability claims for this draft. Those claims are free model access and a free server option.&lt;/p&gt;

&lt;p&gt;This draft does not name any specific model. This draft does not state a token quota. It also does not state hardware, duration, or uptime.&lt;/p&gt;

&lt;p&gt;Check the project docs on the day you run the tool. If the docs disagree with this article, trust the docs. A review habit should not pretend to be a product spec.&lt;/p&gt;

&lt;p&gt;Use the free server so your laptop clone stays untouched. Use free model access so a bounded retry stays cheap. Still copy the patch home and score it locally.&lt;/p&gt;

&lt;h2&gt;
  
  
  Shape the prompt before the call
&lt;/h2&gt;

&lt;p&gt;Write the prompt as four short constraints, not a story. Name the ticket line, the allowed files, the forbidden paths, and the test command. Refuse any reply that skips one of those four.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Ticket: reject empty names in parseName.
Allowed: src/parseName.js src/parseName.test.js
Forbidden: .github migrations package-lock.json .env
Test: npm test -- src/parseName.test.js
Output: a patch only. Do not commit.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep that prompt in the scratch notes beside the packet. If you change the prompt, change the notes too. A later reviewer should see the exact ask.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add a local score script
&lt;/h2&gt;

&lt;p&gt;Save the checker below before you call any model. This script is a proposal, not an executed benchmark. Adapt the blocked path list to your repository.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class="c"&gt;# proposal: unexecuted junior gate for an agent diff&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail

&lt;span class="nv"&gt;BASE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;/main&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;MAX_FILES&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;MAX_FILES&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;8&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;MAX_LINES&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;MAX_LINES&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;200&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

git rev-parse &lt;span class="nt"&gt;--is-inside-work-tree&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;/dev/null
&lt;span class="nv"&gt;FILES&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;git diff &lt;span class="nt"&gt;--name-only&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BASE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;...HEAD"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;COUNT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'%s\n'&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$FILES&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="s1"&gt;'/^$/d'&lt;/span&gt; | &lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt; | &lt;span class="nb"&gt;tr&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;' '&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;STAT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;git diff &lt;span class="nt"&gt;--numstat&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BASE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;...HEAD"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;ADDED&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'%s\n'&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$STAT&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;awk&lt;/span&gt; &lt;span class="s1"&gt;'{s+=$1} END {print s+0}'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;DELETED&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'%s\n'&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$STAT&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;awk&lt;/span&gt; &lt;span class="s1"&gt;'{s+=$2} END {print s+0}'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;LINES&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$((&lt;/span&gt;ADDED &lt;span class="o"&gt;+&lt;/span&gt; DELETED&lt;span class="k"&gt;))&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"files=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;COUNT&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; lines=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;LINES&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="nv"&gt;fail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$COUNT&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-gt&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$MAX_FILES&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"FAIL too many files for hour one"&lt;/span&gt;
  &lt;span class="nv"&gt;fail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1
&lt;span class="k"&gt;fi
if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$LINES&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-gt&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$MAX_LINES&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"FAIL diff too large for hour one"&lt;/span&gt;
  &lt;span class="nv"&gt;fail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1
&lt;span class="k"&gt;fi

&lt;/span&gt;&lt;span class="nv"&gt;BLOCK&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'(^|/)(\.github/workflows/|migrations/|.*lock$|\.env|credentials?)'&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'%s\n'&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$FILES&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$BLOCK&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"FAIL blocked path present in diff"&lt;/span&gt;
  &lt;span class="nv"&gt;fail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1
&lt;span class="k"&gt;fi

if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; REVIEW_PACKET.md &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"FAIL missing REVIEW_PACKET.md"&lt;/span&gt;
  &lt;span class="nv"&gt;fail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1
&lt;span class="k"&gt;else
  &lt;/span&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-q&lt;/span&gt; &lt;span class="s1"&gt;'^Revert: '&lt;/span&gt; REVIEW_PACKET.md &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"FAIL missing Revert line"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;fail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-q&lt;/span&gt; &lt;span class="s1"&gt;'^Test: '&lt;/span&gt; REVIEW_PACKET.md &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"FAIL missing Test line"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;fail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-q&lt;/span&gt; &lt;span class="s1"&gt;'^Unknown hunks: 0$'&lt;/span&gt; REVIEW_PACKET.md &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"FAIL unknown hunks remain"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;fail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;fi

&lt;/span&gt;&lt;span class="nb"&gt;exit&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$fail&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the checker from the scratch branch after you pull the patch. Pass the base ref your team actually uses. Do not open a pull request when the exit code is nonzero.&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;chmod&lt;/span&gt; +x scripts/score-agent-diff.sh
&lt;span class="nv"&gt;MAX_FILES&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;8 &lt;span class="nv"&gt;MAX_LINES&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;200 ./scripts/score-agent-diff.sh origin/main
git diff &lt;span class="nt"&gt;--stat&lt;/span&gt; origin/main...HEAD
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Read the stat output even when the script passes. A rename can still hide a large rewrite. Your own eyes still have to close the gate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Write the packet yourself
&lt;/h2&gt;

&lt;p&gt;Create REVIEW_PACKET.md in the scratch branch before review. You write every line in that packet yourself. Do not accept an agent-written packet as your own note.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;Ticket: ISSUE-123
Test: npm test -- workspace/foo.test.js
Revert: git revert &lt;span class="nt"&gt;&amp;lt;merge-sha&amp;gt;&lt;/span&gt;
Unknown hunks: 0
Risk: parser change only, no schema edit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The test line must name a command you actually ran. If you have not run it, write Test not run and stop. A missing run is a failed gate, not a minor note.&lt;/p&gt;

&lt;p&gt;The revert line must be a command you understand today. If revert would need a data backfill, stop the pull request. Hour one is the wrong time for that class of change.&lt;/p&gt;

&lt;h2&gt;
  
  
  Follow these eight steps
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Copy the ticket acceptance line into your prompt notes.&lt;/li&gt;
&lt;li&gt;Create a scratch branch that is not your pull request branch.&lt;/li&gt;
&lt;li&gt;Start the agent on the free server option, without secrets.&lt;/li&gt;
&lt;li&gt;Limit the prompt to files the ticket actually needs.&lt;/li&gt;
&lt;li&gt;Pull the patch back and run the score script locally.&lt;/li&gt;
&lt;li&gt;Run the test command and record the real result.&lt;/li&gt;
&lt;li&gt;Set unknown hunks to zero only after you explain each hunk.&lt;/li&gt;
&lt;li&gt;Open the pull request only when the script exits zero.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Stop the run if the agent edits a file you did not name. Stop again if the summary mentions a file absent from the diff. Those mismatches mean the packet is not ready.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use this decision table
&lt;/h2&gt;

&lt;p&gt;Do not bargain with a failed row during hour one. Split the work now or discard the scratch branch. Ask a senior when the row is outside your map.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Signal&lt;/th&gt;
&lt;th&gt;Score&lt;/th&gt;
&lt;th&gt;Your move&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Eight files or fewer&lt;/td&gt;
&lt;td&gt;Pass&lt;/td&gt;
&lt;td&gt;Continue to the test line&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;More than 200 changed lines&lt;/td&gt;
&lt;td&gt;Fail&lt;/td&gt;
&lt;td&gt;Split the patch or discard it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Blocked path in the diff&lt;/td&gt;
&lt;td&gt;Fail&lt;/td&gt;
&lt;td&gt;Reset the scratch branch&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Test command not run by you&lt;/td&gt;
&lt;td&gt;Fail&lt;/td&gt;
&lt;td&gt;Run it, or do not open the PR&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Unknown hunk count above zero&lt;/td&gt;
&lt;td&gt;Fail&lt;/td&gt;
&lt;td&gt;Read again or drop that hunk&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Revert line you cannot explain&lt;/td&gt;
&lt;td&gt;Fail&lt;/td&gt;
&lt;td&gt;Write a real revert or stop&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;New dependency or workflow edit&lt;/td&gt;
&lt;td&gt;Fail&lt;/td&gt;
&lt;td&gt;Hand the ticket to a senior&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A passing size score is not a passing meaning score. You still need to read each hunk in order. Opaque code stays a fail until you can teach it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Walk one sample hunk
&lt;/h2&gt;

&lt;p&gt;Imagine the ticket says the parser should reject an empty name. The agent changes parseName and also reformats the README file. You score the parser hunk as related to the ticket.&lt;/p&gt;

&lt;p&gt;You score the README hunk as unknown, then you drop it. That parser hunk matches the ticket, so it can stay. You still run the named test before you open any pull request.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gd"&gt;- if (!name) return null;
&lt;/span&gt;&lt;span class="gi"&gt;+ if (!name || !name.trim()) throw new Error("empty name");
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Treat this diff as an illustration, not as a result from your repo. Replace the function names with the files your ticket names. Keep the same pass or fail questions on every hunk.&lt;/p&gt;

&lt;h2&gt;
  
  
  Read hunks in a fixed order
&lt;/h2&gt;

&lt;p&gt;Open the diff one file at a time. Ask what user-visible behavior changed for this ticket. If the answer needs a guess, mark that hunk unknown.&lt;/p&gt;

&lt;p&gt;Watch for formatter noise spread across unrelated files. Watch for a new helper that the ticket never requested. Watch for a comment that hides a behavior change.&lt;/p&gt;

&lt;p&gt;Compare the agent summary with the name-only diff output. Every file in the summary should appear in that list. Every file in the list should appear in your notes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep the free options in their lane
&lt;/h2&gt;

&lt;p&gt;The free server is only for the noisy first pass. Keep private fixtures and credentials off that machine. Copy a patch back, not a live environment.&lt;/p&gt;

&lt;p&gt;Free model access can make a second prompt cheap. Change the constraint before you retry the same ask. A retry without a new limit is usually noise.&lt;/p&gt;

&lt;p&gt;This article states no token total and no expiry date. Those facts were not supplied as verified numbers. Read the current docs before you plan a long session.&lt;/p&gt;

&lt;p&gt;If your team bans external coding agents, stop here. Do not treat a free tier as a policy workaround. Ask your lead before you send the first prompt.&lt;/p&gt;

&lt;h2&gt;
  
  
  Know the checker limits
&lt;/h2&gt;

&lt;p&gt;The block regex is a starter, not a complete risk map. Add your real danger paths before you trust a pass. A green script can still miss a risky file name.&lt;/p&gt;

&lt;p&gt;Numstat sums ignore binary files and some renames. Run git diff stat when those numbers look too small. Trust the strange stat over the cheerful summary.&lt;/p&gt;

&lt;p&gt;A free server may lack your private test fixtures. A pass on that server can still fail in CI. Prefer the pinned CI command when you can run it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Skip this flow in these cases
&lt;/h2&gt;

&lt;p&gt;Skip the flow when the ticket needs production data. Skip it when you cannot read the language yet. Skip it when the change is a release or a migration.&lt;/p&gt;

&lt;p&gt;Skip it when you need a guaranteed quota or support contract. This draft does not establish either of those promises. Use an approved internal tool when the ticket is urgent.&lt;/p&gt;

&lt;p&gt;Skip it when the diff is already on a shared branch. Hour one should not repair a public mistake with another agent pass. Revert first, then review the result with a human.&lt;/p&gt;

&lt;h2&gt;
  
  
  Leave with a defendable pull request
&lt;/h2&gt;

&lt;p&gt;Your first pull request should stay small enough to explain aloud. The score script is the defense you can show. The model only drafted the patch you scored.&lt;/p&gt;

&lt;p&gt;If you use MonkeyCode for that first pass, read the current notes. Confirm the free-access terms on the day you actually run it. Then run the local gate before you ask anyone for review.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>git</category>
      <category>testing</category>
      <category>ai</category>
    </item>
    <item>
      <title>Gate Your First Agent Patch on a Stable Failure Log</title>
      <dc:creator>Quinn Zhu</dc:creator>
      <pubDate>Sat, 10 Oct 2026 18:42:54 +0000</pubDate>
      <link>https://dev.to/gitgo_5662/gate-your-first-agent-patch-on-a-stable-failure-log-7j0</link>
      <guid>https://dev.to/gitgo_5662/gate-your-first-agent-patch-on-a-stable-failure-log-7j0</guid>
      <description>&lt;p&gt;Save the failing command before any agent edits your repo. A first PR should start from a bundle, not a chat guess. That bundle holds a script, two logs, and a base SHA.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start from the failure
&lt;/h2&gt;

&lt;p&gt;You join the repo and the ticket already sounds urgent. Someone suggests an agent can patch the bug before lunch. You paste the issue text and accept the first diff.&lt;/p&gt;

&lt;p&gt;The reviewer cannot replay that chat on their machine. You also cannot defend a rollback if main breaks later. Hour one should prove the failure, not invent the fix.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you leave behind
&lt;/h2&gt;

&lt;p&gt;You will finish the hour with a small repro directory. It contains a script, two logs, a SHA, and a note. The script must fail the same way on two clean runs.&lt;/p&gt;

&lt;p&gt;You do not open a pull request during this hour. You do not let an agent write files before those runs.&lt;/p&gt;

&lt;p&gt;Keep the names stable so a reviewer can find them fast. Do not rename logs after you paste one into a prompt.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;repro/
  START_SHA
  NOTE
  run.sh
  run-1.log
  run-2.log
  log.diff
  PROMPT_LOG
  run-3.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  1. Freeze the starting SHA
&lt;/h2&gt;

&lt;p&gt;Clone the repository into a new directory on a clean host. Do not reuse a laptop checkout full of old builds. Check out the default branch your team already documents.&lt;/p&gt;

&lt;p&gt;Record the commit SHA before you install extra tools. That file is your anchor if the patch needs a revert. Do not update the SHA after you start the two runs.&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; &lt;span class="nt"&gt;-p&lt;/span&gt; repro
git rev-parse HEAD | &lt;span class="nb"&gt;tee &lt;/span&gt;repro/START_SHA
&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'%s\n'&lt;/span&gt; &lt;span class="s2"&gt;"ticket: &amp;lt;id&amp;gt;"&lt;/span&gt; &lt;span class="s2"&gt;"command: &amp;lt;paste from CI&amp;gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; repro/NOTE
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the branch moves, start the bundle over from clone. A moved base makes the later diff harder to explain.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Copy the command, not the story
&lt;/h2&gt;

&lt;p&gt;Open the ticket and the newest failing CI log. Copy the exact command that failed, including its working directory. Do not shorten the command so the run feels faster.&lt;/p&gt;

&lt;p&gt;Pin package scripts if CI called those scripts by name. Write unknown flags down instead of guessing their meaning.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; repro/run.sh &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;'
#!/usr/bin/env bash
set -euo pipefail
cd "&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;dirname&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="sh"&gt;/.."
# Replace the next line with the exact CI command.
npm test -- workspace/parser
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;span class="nb"&gt;chmod&lt;/span&gt; +x repro/run.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Treat that file as a template until the real command lands. If the log names a setup step, put that step first. Keep secrets out of the script and out of the note.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Run the script twice on a clean host
&lt;/h2&gt;

&lt;p&gt;A laptop cache can hide the bug you are chasing. Run both attempts on a throwaway host instead. A clean host is enough for this narrow check.&lt;/p&gt;

&lt;p&gt;Disclosure: This article was prepared as part of MonkeyCode's product outreach. MonkeyCode offers free model access and a free server option. Use that server only as the clean host for these two runs.&lt;/p&gt;

&lt;p&gt;Use free model access only after the logs match. Do not assume a model name, a quota, or a machine size. Those details are not stated here because they can change.&lt;/p&gt;

&lt;p&gt;Read the current product docs before you depend on access. Confirm the live limits before you store anything there. Treat current access as optional, not as a lasting promise.&lt;/p&gt;

&lt;p&gt;Run the script once and keep every line of output. The true fallback keeps the shell alive after a failed test. You still want the log when the command exits non-zero.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./repro/run.sh &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; repro/run-1.log 2&amp;gt;&amp;amp;1 &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wait a minute, then run the same script again. Save the second log beside the first one. Diff the logs before you decide the failure is real.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./repro/run.sh &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; repro/run-2.log 2&amp;gt;&amp;amp;1 &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true
&lt;/span&gt;diff &lt;span class="nt"&gt;-u&lt;/span&gt; repro/run-1.log repro/run-2.log &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; repro/log.diff &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Stop when the logs disagree in a meaningful way. A flaky failure is a bad target for your first PR.&lt;/p&gt;

&lt;p&gt;Write the mismatch in the ticket and ask a human. Do not ask a model to hide flake with retries.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Read the log before you prompt
&lt;/h2&gt;

&lt;p&gt;Read the log from the bottom, not from the top. Find the first error that names a file and a line. Ignore warnings that also appear on a green main build.&lt;/p&gt;

&lt;p&gt;If you cannot tie the error to a file, stop here. A vague failure needs a human, not a generated patch.&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;tail&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; 40 repro/run-2.log &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; repro/PROMPT_LOG
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  5. Ask for a patch only after the logs match
&lt;/h2&gt;

&lt;p&gt;Open a chat only after the two logs agree. Attach the script, the SHA, and the second log. Ask for a patch that makes this script pass.&lt;/p&gt;

&lt;p&gt;Ask for the file list before you ask for code. Reject any reply that ignores the script you saved. Keep the prompt short so a free model can answer.&lt;/p&gt;

&lt;p&gt;Trim the saved log before you paste it into a chat. Forty lines is a starting cap, not a measured limit. Never paste tokens, customer rows, or private URLs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Base SHA: &amp;lt;paste repro/START_SHA&amp;gt;
Command: ./repro/run.sh
Failure log: &amp;lt;paste repro/PROMPT_LOG&amp;gt;
Constraint: change the smallest set of files.
Do not add dependencies.
Return a file list, a patch, and one short reason.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the ticket needs those, use the private runner. Treat the answer as an unexecuted proposal, not a result. You still have to apply it and rerun the script.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Apply it on a branch and rerun
&lt;/h2&gt;

&lt;p&gt;Create a branch from the SHA you already recorded. Apply a short patch by hand so you see each hunk. Do not apply a patch that adds new dependencies.&lt;/p&gt;

&lt;p&gt;Run the same script and save a third log. Compare the second log with the third log yourself. The old error text should be gone in the third log.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git checkout &lt;span class="nt"&gt;-b&lt;/span&gt; junior/repro-fix &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;repro/START_SHA&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="c"&gt;# Apply the reviewed patch by hand, then:&lt;/span&gt;
./repro/run.sh &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; repro/run-3.log 2&amp;gt;&amp;amp;1 &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Other tests in that command should not start failing. If they fail, revert the branch and keep the bundle. Map every hunk to a line in the failure log.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git diff &lt;span class="nt"&gt;--stat&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;repro/START_SHA&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If a hunk has no story, the patch is too wide. Cut the extra files and ask for a smaller patch.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Write the PR so a stranger can replay it
&lt;/h2&gt;

&lt;p&gt;Open the PR only when you can narrate the diff. Put the script path and the base SHA in the body.&lt;/p&gt;

&lt;p&gt;Name the command you ran and the log you compared. Invite review of the bundle, not praise of the agent.&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="gu"&gt;## Repro&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Base SHA: &lt;span class="nt"&gt;&amp;lt;paste&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Script: repro/run.sh
&lt;span class="p"&gt;-&lt;/span&gt; Compared: repro/run-2.log and repro/run-3.log

&lt;span class="gu"&gt;## What changed&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;file&amp;gt;&lt;/span&gt;: &lt;span class="nt"&gt;&amp;lt;one&lt;/span&gt; &lt;span class="na"&gt;sentence&lt;/span&gt; &lt;span class="na"&gt;tied&lt;/span&gt; &lt;span class="na"&gt;to&lt;/span&gt; &lt;span class="na"&gt;the&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt; &lt;span class="na"&gt;line&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="gu"&gt;## Rollback&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Revert this branch if a hunk cannot be explained.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  8. Roll back the same day if the story breaks
&lt;/h2&gt;

&lt;p&gt;Roll back the same day if review exposes a gap. A clean revert is better than a clever unexplained patch. Follow your team's revert rule if the merge was squashed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Use your team's documented revert path after merge.&lt;/span&gt;
git revert &lt;span class="nt"&gt;--no-edit&lt;/span&gt; &amp;lt;merged-commit&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Leave the bundle in the ticket after the revert. The next person can rerun it without your laptop. Do not delete the logs just because the PR closed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decision table
&lt;/h2&gt;

&lt;p&gt;Use this table as a gate before you push. It is a checklist, not a scoreboard for speed.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Signal&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Two logs match and name one error&lt;/td&gt;
&lt;td&gt;Ask for a small patch&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Logs differ, or the run hangs&lt;/td&gt;
&lt;td&gt;Stop and ask a human about flake&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Patch touches files outside the stack&lt;/td&gt;
&lt;td&gt;Reject it and re-ask with a file cap&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Script passes but one hunk has no story&lt;/td&gt;
&lt;td&gt;Revert and do not merge&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ticket includes secrets or production data&lt;/td&gt;
&lt;td&gt;Do not use an external host or chat&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Print the table and keep it next to the ticket. If a row says stop, stop before you prompt again.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limits to say out loud
&lt;/h2&gt;

&lt;p&gt;This method fits one failing command with a stable log. It does not fit races, load tests, or hardware bugs. Two matching runs do not prove a rare crash is gone.&lt;/p&gt;

&lt;p&gt;A free server may sleep, throttle, or disappear later. Do not call that host your team's continuous integration. Do not store credentials or production dumps on it.&lt;/p&gt;

&lt;p&gt;Free model access may reject a very long log. Trim to the failing section and send that slice only. The commands in this article are an unexecuted example.&lt;/p&gt;

&lt;p&gt;They are a workflow to adapt, not a measured benchmark. No timings, pass rates, or hardware claims belong here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who should skip this
&lt;/h2&gt;

&lt;p&gt;Skip this if your team forbids external code hosts. Skip this if the bug needs a private dataset. Skip this if you are on call for a live incident.&lt;/p&gt;

&lt;p&gt;Senior engineers chasing a multi-service outage need another plan. New hires with a documented unit-test failure are the fit. If your mentor already owns the patch, pair with them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Close the hour
&lt;/h2&gt;

&lt;p&gt;Hour one ends with a bundle, not a hero patch. Save the SHA, the script, and two matching logs.&lt;/p&gt;

&lt;p&gt;Ask for a patch only after that evidence exists. If the diff outruns your explanation, revert it today.&lt;/p&gt;

&lt;p&gt;If you already have that free server, run the two checks there. Keep the prompt tied to the saved logs only. Check the docs your team trusts before you rely on availability.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>git</category>
      <category>testing</category>
      <category>ai</category>
    </item>
    <item>
      <title>Classify Repo Paths Before Your First Agent Prompt</title>
      <dc:creator>Quinn Zhu</dc:creator>
      <pubDate>Fri, 09 Oct 2026 15:02:39 +0000</pubDate>
      <link>https://dev.to/gitgo_5662/classify-repo-paths-before-your-first-agent-prompt-20cc</link>
      <guid>https://dev.to/gitgo_5662/classify-repo-paths-before-your-first-agent-prompt-20cc</guid>
      <description>&lt;h1&gt;
  
  
  Classify Repo Paths Before Your First Agent Prompt
&lt;/h1&gt;

&lt;p&gt;Your first agent prompt needs a written path map. A junior can leak secrets with one careless paste. Classify every path before any model sees the repo.&lt;/p&gt;

&lt;p&gt;This hour is about refusal, not about shipping a fix. You will build a small path classifier first. You will not prompt until that map is green.&lt;/p&gt;

&lt;h2&gt;
  
  
  What hour one can break
&lt;/h2&gt;

&lt;p&gt;You just cloned a repo you barely know. The agent offers to look around and fix tests. That browse can read tokens and customer fixtures.&lt;/p&gt;

&lt;p&gt;A hosted model may retain what you upload. A free server is still someone else's computer. Treat both as untrusted until policy says otherwise.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three buckets, one decision
&lt;/h2&gt;

&lt;p&gt;Give every path one bucket before you prompt. Read-only context may be summarized, not edited. The sandbox is the only tree the agent may change.&lt;/p&gt;

&lt;p&gt;Forbidden paths never enter the prompt or the upload. Env files, key files, and prod configs belong there. If you feel unsure, mark the path forbidden.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Freeze a toy tree
&lt;/h2&gt;

&lt;p&gt;Do not point this drill at a production clone. Use a fixture repo your lead already approved. Create a branch that nobody will merge today.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git switch &lt;span class="nt"&gt;-c&lt;/span&gt; onboard/path-map
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; sandbox fixtures/secrets docs
&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'Toy repo for a path-map drill.\n'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; README.md
&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'print("ok")\n'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; sandbox/hello.py
&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'TOKEN=replace-me\n'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; fixtures/secrets/.env
&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'Not a real secret.\n'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; docs/notes.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Those sample files are examples, not live secrets. Delete the fixture when the drill is done. Never copy a live credential into this tree.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Write the rule file
&lt;/h2&gt;

&lt;p&gt;Keep rules in the repo only with lead approval. Otherwise store the map in your private notes. Start from a plain text file named path-map.txt.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# path-map.txt - example rules, edit before use
read_only:
  README.md
  docs/
sandbox:
  sandbox/
forbidden:
  .env
  .env.*
  fixtures/secrets/
  *.pem
  infra/prod/
local_tool:
  path-map.txt
  classify-paths.sh
  path-report.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Put one rule on each line for easy review. A glob you cannot explain should stay forbidden. Ask your buddy before you widen the sandbox.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Run a local classifier
&lt;/h2&gt;

&lt;p&gt;Read this script before you execute a single line. It does not call a network or an agent. It only prints a bucket for each file path.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class="c"&gt;# Unexecuted example. Prefix checks only. No network calls.&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail

find &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-type&lt;/span&gt; f &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nt"&gt;-path&lt;/span&gt; &lt;span class="s1"&gt;'./.git/*'&lt;/span&gt; | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="s1"&gt;'s#^./##'&lt;/span&gt; | &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nv"&gt;IFS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;read&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; rel&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
  case&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$rel&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
    .env|.env.&lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="k"&gt;*&lt;/span&gt;/.env|&lt;span class="k"&gt;*&lt;/span&gt;/.env.&lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;fixtures/secrets/&lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="k"&gt;*&lt;/span&gt;.pem|infra/prod/&lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"forbidden &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;rel&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
      &lt;span class="p"&gt;;;&lt;/span&gt;
    sandbox/&lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"sandbox &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;rel&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
      &lt;span class="p"&gt;;;&lt;/span&gt;
    README.md|docs/&lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"read_only &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;rel&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
      &lt;span class="p"&gt;;;&lt;/span&gt;
    path-map.txt|classify-paths.sh|path-report.txt&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"local_tool &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;rel&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
      &lt;span class="p"&gt;;;&lt;/span&gt;
    &lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"unmapped &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;rel&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
      &lt;span class="p"&gt;;;&lt;/span&gt;
  &lt;span class="k"&gt;esac&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Treat the script as an unexecuted example first. An unmapped file should block the prompt completely. You do not guess a bucket under time pressure.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Fail closed on gaps
&lt;/h2&gt;

&lt;p&gt;Count the report lines before you continue today. An unmapped count above zero stops the session. A forbidden count tells you what never gets uploaded.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bash classify-paths.sh | &lt;span class="nb"&gt;tee &lt;/span&gt;path-report.txt
&lt;span class="nb"&gt;awk&lt;/span&gt; &lt;span class="s1"&gt;'/^unmapped /{c++} END{print c+0}'&lt;/span&gt; path-report.txt
&lt;span class="nb"&gt;awk&lt;/span&gt; &lt;span class="s1"&gt;'/^forbidden /{c++} END{print c+0}'&lt;/span&gt; path-report.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the unmapped count is not zero, fix the map. Keep every forbidden path out of the prompt text. Then rerun both counts and save the report.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Pick a machine with a table
&lt;/h2&gt;

&lt;p&gt;Use this table before you choose a machine. Your written company policy beats every row below. When policy is silent, do not upload the repo.&lt;/p&gt;

&lt;p&gt;Disclosure: This article was prepared as part of MonkeyCode's product outreach. MonkeyCode offers free model access and a free server option. This article does not name models, quotas, or duration.&lt;/p&gt;

&lt;p&gt;Those terms change, so read the current product page. Do not paste the sample token into any prompt. Do not upload payroll files to a free server.&lt;/p&gt;

&lt;p&gt;A free tier is not a data-processing agreement. Check retention terms before you type a prompt. Stop if those terms conflict with your handbook.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Situation&lt;/th&gt;
&lt;th&gt;Where to run&lt;/th&gt;
&lt;th&gt;What you may upload&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Policy forbids external models&lt;/td&gt;
&lt;td&gt;Approved laptop only&lt;/td&gt;
&lt;td&gt;Nothing leaves the machine&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Policy allows a hosted spike&lt;/td&gt;
&lt;td&gt;Free server, if still offered&lt;/td&gt;
&lt;td&gt;Toy repo or redacted sandbox&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;You want a hosted model&lt;/td&gt;
&lt;td&gt;Free model access, if offered&lt;/td&gt;
&lt;td&gt;Same allowlist, no forbidden paths&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Live credentials sit on disk&lt;/td&gt;
&lt;td&gt;Do not start the agent&lt;/td&gt;
&lt;td&gt;Stop and ask your lead&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  6. Lock a prompt contract
&lt;/h2&gt;

&lt;p&gt;Paste the contract above the task, not below it. Keep the task limited to one sandbox file. Refuse any request to scan the whole repo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Path contract:
- Edit only sandbox/hello.py.
- Do not open fixtures/secrets or any env file.
- Do not add dependencies.
- Stop if a needed file is unmapped.
Task: add a one-line comment that says hello.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You review the diff yourself after the run. You do not merge from the agent summary alone. If the diff touches a forbidden path, discard the branch.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Reset before any pull request
&lt;/h2&gt;

&lt;p&gt;This drill ends in a reset, not a merge. You are proving you can undo agent edits. You are not shipping product code on day one.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git status &lt;span class="nt"&gt;--short&lt;/span&gt;
git diff &lt;span class="nt"&gt;--&lt;/span&gt; sandbox/hello.py
git restore &lt;span class="nt"&gt;--&lt;/span&gt; sandbox/hello.py
&lt;span class="c"&gt;# Switch back to the branch you started from, then:&lt;/span&gt;
git branch &lt;span class="nt"&gt;-D&lt;/span&gt; onboard/path-map
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Confirm the sandbox file matches the original bytes. Confirm the secret fixture never entered a commit. Then tell your buddy what you refused to upload.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limits you should say aloud
&lt;/h2&gt;

&lt;p&gt;This classifier is a text filter, not a boundary. A model can still infer secrets from pasted logs. The sample globs are narrow on purpose today.&lt;/p&gt;

&lt;p&gt;The script does not follow symlinks or submodules. It will miss a renamed env file easily. You still need human review on every diff.&lt;/p&gt;

&lt;p&gt;Free model access can change or disappear later. A free server may retain prompts under its terms. Neither offer replaces your team's vendor review.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who should skip this
&lt;/h2&gt;

&lt;p&gt;Skip this if a sealed devcontainer is already required. Skip this if no redacted fixture is allowed. Skip this if you cannot name the editable file.&lt;/p&gt;

&lt;p&gt;Staff with a written agent policy need stricter controls. This drill is for hour one, not production automation. Do not point it at a live customer tenant.&lt;/p&gt;

&lt;h2&gt;
  
  
  After the map is green
&lt;/h2&gt;

&lt;p&gt;Ask your buddy to spot-check the path report. If they approve a hosted spike, open the MonkeyCode terms. Confirm the free options still match team policy.&lt;/p&gt;

&lt;p&gt;Run the same contract on the toy repo only. Your first real PR waits until you can explain every line.&lt;/p&gt;

&lt;p&gt;The path map is the note you keep nearby. Repeat that map on the next ticket before prompting.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Show your lead a receipt
&lt;/h2&gt;

&lt;p&gt;Bring a short receipt to your onboarding lead. Include the branch name and the report counts. Include the list of paths you refused to upload.&lt;/p&gt;

&lt;p&gt;Say which machine ran the classifier and why. Say whether any prompt left your laptop today. If a prompt left, attach the exact contract text.&lt;/p&gt;

&lt;p&gt;If no prompt left, say that in one line. Ask which bucket was wrong before the next ticket.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>git</category>
      <category>ai</category>
      <category>career</category>
    </item>
    <item>
      <title>Move the First Agent Run Off Your Laptop Clone</title>
      <dc:creator>Quinn Zhu</dc:creator>
      <pubDate>Thu, 08 Oct 2026 10:30:27 +0000</pubDate>
      <link>https://dev.to/gitgo_5662/move-the-first-agent-run-off-your-laptop-clone-1pcm</link>
      <guid>https://dev.to/gitgo_5662/move-the-first-agent-run-off-your-laptop-clone-1pcm</guid>
      <description>&lt;p&gt;Do not let your first agent edit land in the laptop clone. Run that first session on a remote sandbox instead. Bring back one reviewed patch after the checks pass.&lt;/p&gt;

&lt;p&gt;You joined this repository with a thin map of its risks. A coding agent can still draft a small change for you. That speed is not a safe first pull request.&lt;/p&gt;

&lt;p&gt;Keep the default branch untouched during this first hour. Explain every changed line before you request review. Treat the steps below as a proposal you must adapt.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Write the Contract Before You Open a Chat
&lt;/h2&gt;

&lt;p&gt;Write a one-page brief before you open an agent chat. The brief is the only contract for this hour. If the brief feels vague, do not start the session.&lt;/p&gt;

&lt;p&gt;Lock five facts in that brief before you type a prompt. Name the ticket and the one behavior you will change. Also name allowed paths, the CI test command, and the base SHA.&lt;/p&gt;

&lt;p&gt;Do not ask the agent to invent those facts for you. You write them from the repository and the ticket. The agent may work only inside that written fence.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Record the Base Commit Before Any Agent Prompt
&lt;/h2&gt;

&lt;p&gt;Your first commands should only read local repository state. They should not create an agent branch on this clone. Save the default-branch SHA where you can find it later.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git fetch origin
git status &lt;span class="nt"&gt;--short&lt;/span&gt;
git rev-parse &lt;span class="nt"&gt;--abbrev-ref&lt;/span&gt; HEAD
git rev-parse origin/main
git log &lt;span class="nt"&gt;-1&lt;/span&gt; &lt;span class="nt"&gt;--oneline&lt;/span&gt; origin/main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Write that SHA into a note outside the work tree. If this repository uses master, record that name instead. This note is your return point if the session goes wide.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git rev-parse origin/main &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/hour-one-base.txt"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do not commit that personal note into the repository. Do not push it to the remote by mistake either. It is a personal checkpoint, not a project file.&lt;/p&gt;

&lt;p&gt;Confirm the work tree is clean before you continue. A dirty clone will mix your scraps with the agent patch. Stash or drop those scraps before you record the base.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Pick a Sandbox That Is Not Your Clone
&lt;/h2&gt;

&lt;p&gt;You need a place the agent can edit without touching your clone. A free server can be that place when the offer includes one. A local virtual machine remains a valid substitute here.&lt;/p&gt;

&lt;p&gt;Disclosure: This article was prepared as part of MonkeyCode's product outreach.&lt;/p&gt;

&lt;p&gt;MonkeyCode is only one route to free model access and a free server. Treat both items as availability claims that you must recheck today. This article does not name models, token caps, hardware, or duration.&lt;/p&gt;

&lt;p&gt;Those details change, and this draft did not measure them. Open the current product page before you depend on any limit. If the free server is absent, keep the same brief locally.&lt;/p&gt;

&lt;p&gt;Use that server only for this first reviewed patch. Do not place production secrets on that remote machine. Do not point the session at private customer data.&lt;/p&gt;

&lt;p&gt;If the repository is private, read the server terms first. If those terms are unclear, skip the remote option entirely. A company ban on outside models also ends this path.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Copy a Narrow Brief Onto the Sandbox
&lt;/h2&gt;

&lt;p&gt;Create a file named SESSION_BRIEF.md on the sandbox before prompting. Keep that file short enough to reread in two minutes. The sample below is an unexecuted template, not a real run.&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;# Session brief&lt;/span&gt;
Ticket: https://example.test/tickets/123
Change: Adjust empty-state copy in web/src/Empty.tsx only.
Allow: web/src/Empty.tsx and web/src/Empty.test.tsx
Outside scope: workflows, lockfiles, migrations, and infra
Test: npm test -- Empty.test.tsx
Done: that test passes, and no other file changes.
Stop: if a new dependency is required, stop.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Paste the brief as your first message to the agent. Tell the agent to stop when the change leaves those files. Tell it not to push or open a pull request.&lt;/p&gt;

&lt;p&gt;Tell it not to amend commits or rewrite history. If the agent leaves the allowed files, discard the sandbox. Do not salvage a wide diff on your first day.&lt;/p&gt;

&lt;p&gt;Start again later with a smaller allowed file list. Watch the session for scope creep in the chat replies. A request to update a lockfile is a stop signal.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Export One Patch and Leave the Sandbox
&lt;/h2&gt;

&lt;p&gt;On the sandbox, read status before you export anything. You want a single patch file copied to your laptop. You do not want a surprise push to the team remote.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git status &lt;span class="nt"&gt;--short&lt;/span&gt;
git diff &lt;span class="nt"&gt;--stat&lt;/span&gt;
git diff &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /tmp/hour-one.patch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy that patch home through your normal file transfer step. Remove any secrets you typed into the sandbox session. Stop or destroy that server when the product lets you.&lt;/p&gt;

&lt;p&gt;Do not keep a forgotten remote checkout for later experiments. Hour one ends when the reviewed patch is home. A living sandbox is not a second source of truth.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Apply the Patch on a Named Ticket Branch
&lt;/h2&gt;

&lt;p&gt;Return to the laptop clone after the patch is home. Create a branch that names the ticket, not the tool. Test the patch with an apply check before you apply it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git fetch origin
git switch &lt;span class="nt"&gt;-c&lt;/span&gt; ticket-123-empty-state origin/main
git apply &lt;span class="nt"&gt;--check&lt;/span&gt; /tmp/hour-one.patch
git apply /tmp/hour-one.patch
git diff &lt;span class="nt"&gt;--stat&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the default branch moved, do not rebase alone. Ask a human owner before you replay the patch. If the apply check fails, stop and do not hand-merge.&lt;/p&gt;

&lt;p&gt;A confused patch is a failed hour, not a puzzle. Rerun the sandbox session with a smaller written brief. Leave the laptop clone clean while you do that rerun.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Run the Named Test and Read Every Hunk
&lt;/h2&gt;

&lt;p&gt;Run only the test command you wrote in the brief. A full local suite can wait for CI on this pass. You need proof that this patch matches the ticket text.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; Empty.test.tsx
git diff &lt;span class="nt"&gt;--&lt;/span&gt; web/src/Empty.tsx web/src/Empty.test.tsx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace that npm command with the one CI already runs. Do not invent a friendlier command just for the agent. If CI uses a task runner, pin that exact task in the brief.&lt;/p&gt;

&lt;p&gt;Write a reviewer note in your own words after the test. Use the checklist below before you open any pull request. The checklist is an unexecuted proposal, not a team form.&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="p"&gt;-&lt;/span&gt; [ ] I can name the user-visible change in one sentence.
&lt;span class="p"&gt;-&lt;/span&gt; [ ] I can name the test that now covers that change.
&lt;span class="p"&gt;-&lt;/span&gt; [ ] No lockfile, workflow, or migration file changed.
&lt;span class="p"&gt;-&lt;/span&gt; [ ] No new dependency appeared in the diff.
&lt;span class="p"&gt;-&lt;/span&gt; [ ] I can delete this branch without touching main.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you cannot check a box, do not open the pull request. Shrink the patch or drop it and restart from the brief. Silence is better than a review you cannot defend.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Use a Decision Table Before You Continue
&lt;/h2&gt;

&lt;p&gt;This table is a proposal, not an official team policy. Read the row that matches the diff you actually have. Then do that action, even if the agent sounded confident.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;What you see&lt;/th&gt;
&lt;th&gt;What you do&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Only allowed files changed, and the named test passes&lt;/td&gt;
&lt;td&gt;Open a draft pull request&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The patch touches files outside the brief&lt;/td&gt;
&lt;td&gt;Discard the sandbox result and restart&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A new dependency or workflow edit appears&lt;/td&gt;
&lt;td&gt;Stop and ask the code owner&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The patch does not apply on the base&lt;/td&gt;
&lt;td&gt;Do not hand-merge; rerun a smaller brief&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;You cannot explain one hunk&lt;/td&gt;
&lt;td&gt;Do not request review&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Confidence in the chat transcript is not evidence for you. The diff on disk is the evidence you can defend. Your short note is what the reviewer will actually trust.&lt;/p&gt;

&lt;h2&gt;
  
  
  9. Open the First Pull Request as a Draft
&lt;/h2&gt;

&lt;p&gt;Push only the ticket branch from the laptop clone. Open the pull request as a draft, not as ready review. Paste the brief, the test command, and the base SHA.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git push &lt;span class="nt"&gt;-u&lt;/span&gt; origin HEAD
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Write that body yourself after you finish reading the diff. Do not paste the agent transcript as the description text. Reviewers need the change, the test, and the risk.&lt;/p&gt;

&lt;p&gt;They do not need the full chat log in the body. They need to see that you understood each hunk. A short body beats a long generated summary every time.&lt;/p&gt;

&lt;p&gt;Request review only after the draft checks are green. If CI uses a different command, trust the pipeline. Update the brief, rerun that command, and then ask.&lt;/p&gt;

&lt;p&gt;Do not argue with the pipeline on your first day. Do not weaken a check just to make the patch green. Ask the code owner before you touch any workflow file.&lt;/p&gt;

&lt;h2&gt;
  
  
  10. Close a Bad Draft Without Extra Story
&lt;/h2&gt;

&lt;p&gt;Some drafts should die before anyone spends review time. Close the pull request and delete the ticket branch. Then confirm your clone still matches the fetched default branch.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git switch main
git fetch origin
git status &lt;span class="nt"&gt;--short&lt;/span&gt;
git push origin &lt;span class="nt"&gt;--delete&lt;/span&gt; ticket-123-empty-state
git branch &lt;span class="nt"&gt;-D&lt;/span&gt; ticket-123-empty-state
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do this when the patch grew past the written brief. Do this when a reread still leaves one hunk unexplained. A closed draft is a clean outcome, not a failure story.&lt;/p&gt;

&lt;p&gt;If you already merged, follow your team revert rule instead. This article does not invent a revert policy for shared history. Ask the owner before you rewrite commits on the default branch.&lt;/p&gt;

&lt;p&gt;Confirm the default branch SHA before you delete local work. If origin main moved, fetch and read the new log first. Never reset a shared branch to your hour-one note.&lt;/p&gt;

&lt;h2&gt;
  
  
  Respect Limits Before You Trust Free Access
&lt;/h2&gt;

&lt;p&gt;This workflow fits a small, reversible text or copy change. It does not fit migrations, auth changes, or billing code. It does not fit code you cannot place on a third-party server.&lt;/p&gt;

&lt;p&gt;Skip the free server when private-repo terms are still unclear. Skip free model access when your company bans outside models. A local editor plus the same brief is enough in that case.&lt;/p&gt;

&lt;p&gt;Free access can change or disappear without prior notice. Do not plan a week of work on an unpaid server. Do not assume a token grant, machine size, or time limit.&lt;/p&gt;

&lt;p&gt;Verify those facts on the current product page yourself. The sample test command is generic on purpose here. Your repo may use pytest, go test, or a task runner.&lt;/p&gt;

&lt;p&gt;Pin the command your CI configuration already runs today. Do not invent a new command so the agent looks fast. A green command that CI ignores is not a valid signal.&lt;/p&gt;

&lt;p&gt;The template paths are fiction for this teaching example. Replace them with a real file named in your ticket. If you have no ticket, do not invent work for the agent.&lt;/p&gt;

&lt;h2&gt;
  
  
  Skip This Path When the Fit Is Wrong
&lt;/h2&gt;

&lt;p&gt;Skip this path if you cannot read a unified diff yet. Pair with a human before you invite an agent in. An agent does not replace that first reading hour.&lt;/p&gt;

&lt;p&gt;Skip this path for production hotfixes and incident channels. Skip it for mass edits across issues you do not understand. A first contribution still needs the project guide and the license.&lt;/p&gt;

&lt;p&gt;Skip the remote sandbox if it would hide work from review. The patch still comes home to your laptop clone. Your name stays on the pull request either way.&lt;/p&gt;

&lt;p&gt;Do not use this flow to bypass code owner rules. Do not use it to skip a required design note. If the ticket lacks checks, write them with your mentor first.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try One Ticket and Then Stop Cold
&lt;/h2&gt;

&lt;p&gt;If those free options are still listed, try exactly one ticket. Keep the written brief tighter than the prompt you want. If that offer is gone, use a local virtual machine instead.&lt;/p&gt;

&lt;p&gt;Stop after one reviewed draft leaves your laptop. Hour one builds a habit, not a batch of agent pulls. Tomorrow, repeat the brief before you touch a second file.&lt;/p&gt;

</description>
      <category>git</category>
      <category>beginners</category>
      <category>tutorial</category>
      <category>ai</category>
    </item>
    <item>
      <title>Keep Hour-One Exploration Off Your First PR Branch</title>
      <dc:creator>Quinn Zhu</dc:creator>
      <pubDate>Thu, 08 Oct 2026 08:06:50 +0000</pubDate>
      <link>https://dev.to/gitgo_5662/keep-hour-one-exploration-off-your-first-pr-branch-5hcn</link>
      <guid>https://dev.to/gitgo_5662/keep-hour-one-exploration-off-your-first-pr-branch-5hcn</guid>
      <description>&lt;p&gt;Do not let an agent edit your first pull request branch. Explore on a separate clone or a free server. Bring notes back and leave the surprise diff behind.&lt;/p&gt;

&lt;p&gt;You just joined, so the repository still feels opaque. An agent can read faster than you can judge. That speed becomes a liability on your first pull request.&lt;/p&gt;

&lt;h2&gt;
  
  
  The failure you are preventing
&lt;/h2&gt;

&lt;p&gt;The agent edits the same clone you plan to push. You skim a wide diff and approve your own confusion. Reviewers then ask why an unrelated file moved.&lt;/p&gt;

&lt;p&gt;Rollback turns into a search instead of a known sequence. Your first hour should prevent that search entirely. Pins come first, and generated patches come later.&lt;/p&gt;

&lt;p&gt;A junior pull request fails in a quiet way. The code may even pass a local check. The author still cannot explain the change.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pin three facts before any prompt
&lt;/h2&gt;

&lt;p&gt;You need three written facts before the first prompt. Keep them in a local note beside the clone. Do not let the agent edit that note.&lt;/p&gt;

&lt;p&gt;Store that note outside the branch you will ship. A committed pin can be rewritten by the next edit. Your copy should survive a reset.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Capture the branch contract
&lt;/h3&gt;

&lt;p&gt;Run these commands from the clone you control. Save the raw output before you interpret it. Confirm the default branch before you create work.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git remote &lt;span class="nt"&gt;-v&lt;/span&gt;
git status &lt;span class="nt"&gt;--short&lt;/span&gt; &lt;span class="nt"&gt;--branch&lt;/span&gt;
git symbolic-ref &lt;span class="nt"&gt;--short&lt;/span&gt; HEAD
git rev-parse &lt;span class="nt"&gt;--abbrev-ref&lt;/span&gt; origin/HEAD
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If origin HEAD is unset, ask a teammate before guessing. Do not assume main when the repo tracks trunk. A wrong base branch wastes the entire first review.&lt;/p&gt;

&lt;p&gt;Record the remote name next to the default branch. Later commands fail when you hard-code origin. That one line saves a messy recovery.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Name the review surface
&lt;/h3&gt;

&lt;p&gt;List the files you must reread before any push. Start with entry points, config, and auth boundaries. Add each path your ticket names in writing.&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;# review-surface.md&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; default_branch:
&lt;span class="p"&gt;-&lt;/span&gt; base_remote:
&lt;span class="p"&gt;-&lt;/span&gt; must_reread:
&lt;span class="p"&gt;  -&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; checks_i_will_run:
&lt;span class="p"&gt;  -&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; out_of_scope:
&lt;span class="p"&gt;  -&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You fill this file yourself, and the agent does not. If a path is unclear, leave the bullet blank. A blank line is safer than invented certainty.&lt;/p&gt;

&lt;p&gt;Name one check you can run without extra setup. A test command you cannot find is not a plan. Ask where the project documents that command.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Write the rollback card before the diff
&lt;/h3&gt;

&lt;p&gt;Write the revert sequence before any agent edit. Use placeholders until a real merge SHA exists. A card you cannot find is not a plan.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Proposal only. Fill the SHA after the PR merges.&lt;/span&gt;
&lt;span class="c"&gt;# Do not run this until you intend to revert.&lt;/span&gt;
git switch &amp;lt;default-branch&amp;gt;
git pull &lt;span class="nt"&gt;--ff-only&lt;/span&gt;
git revert &lt;span class="nt"&gt;--no-edit&lt;/span&gt; &amp;lt;merge-sha&amp;gt;
git push origin HEAD
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Label the card as a proposal, not a result. Do not invent a SHA just to look ready. The sequence matters more than a guessed hash.&lt;/p&gt;

&lt;p&gt;Keep the card next to the review surface. If you need help, you can show both. A reviewer can correct the sequence early.&lt;/p&gt;

&lt;h2&gt;
  
  
  Explore away from the branch you will ship
&lt;/h2&gt;

&lt;p&gt;You can read the repo with MonkeyCode free model access. A free server option can host that reading session. Disclosure: This article was prepared as part of MonkeyCode's product outreach.&lt;/p&gt;

&lt;p&gt;Confirm the current offer in the product before you rely on it. Do not assume a model name, a token quota, or a machine size. Treat availability as something you recheck, not a permanent promise.&lt;/p&gt;

&lt;p&gt;Use that session to map the ticket, not to push. Do not paste secrets, tokens, or production environment files. Do not add the server remote to your pull request branch.&lt;/p&gt;

&lt;p&gt;Copy notes back in words you can defend aloud. Retype any small patch you decide to keep. A pasted agent diff is not yet your change.&lt;/p&gt;

&lt;p&gt;If the free server is unavailable, use a second local clone. The boundary matters more than the hosting choice. Your pull request branch stays untouched either way.&lt;/p&gt;

&lt;h2&gt;
  
  
  A reading prompt, labeled as a proposal
&lt;/h2&gt;

&lt;p&gt;This is a reading prompt, not a license to edit. Paste it only inside the separate explore session. Replace the ticket line before you send it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Map this ticket. Do not edit files. Do not propose a full patch.
Ticket: &amp;lt;paste the ticket title only&amp;gt;
Return:
1. Files I should reread.
2. Commands I should run locally.
3. Risks if I change the wrong file.
Stop if you need secrets or production data.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Reject any reply that includes a commit or a push. Reject any reply that asks you to paste credentials. Keep the map, then do the reading on your clone.&lt;/p&gt;

&lt;p&gt;Treat the reply as a hint list, not as truth. Open each named file and confirm it exists. Drop any path the repository does not contain.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decision table: what may cross back
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Item&lt;/th&gt;
&lt;th&gt;Cross back?&lt;/th&gt;
&lt;th&gt;Rule you apply&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Notes you rewrote&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;You can explain each line&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Command output&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Strip tokens, emails, and host secrets&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Generated patch&lt;/td&gt;
&lt;td&gt;Only after retype&lt;/td&gt;
&lt;td&gt;You run the listed checks yourself&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Env files or keys&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Stop and rotate if they were copied&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Unrequested lockfile edits&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Leave them out of the first PR&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Suggested commit message&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;You write the message after the diff&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Read the table before you copy anything home. If a row says no, delete that content locally. When unsure, keep the note and drop the patch.&lt;/p&gt;

&lt;p&gt;A useful map names files, risks, and local commands. A risky map includes secrets or a ready-made branch. Choose the map you can repeat without the agent.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hour-one steps you can repeat
&lt;/h2&gt;

&lt;p&gt;Follow this order on the day you join. Do not skip to a prompt because the ticket looks small. Small tickets can still touch shared project files.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Clone the repository into a path you control.&lt;/li&gt;
&lt;li&gt;Run the branch-contract commands and store the output.&lt;/li&gt;
&lt;li&gt;Fill review-surface.md before you write a prompt.&lt;/li&gt;
&lt;li&gt;Write the rollback card with placeholders only.&lt;/li&gt;
&lt;li&gt;Open the explore session away from that clone.&lt;/li&gt;
&lt;li&gt;Ask for a file map of the ticket, not a patch.&lt;/li&gt;
&lt;li&gt;Bring rewritten notes back and update the surface file.&lt;/li&gt;
&lt;li&gt;Create the pull request branch only after those pins exist.&lt;/li&gt;
&lt;li&gt;Limit the diff to files you listed as in scope.&lt;/li&gt;
&lt;li&gt;Run the checks you named, then open the pull request.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Stop at the first step you cannot complete honestly. Hour one can end with pins and no pull request. That outcome is still a successful join day.&lt;/p&gt;

&lt;h2&gt;
  
  
  How you know the notes are yours
&lt;/h2&gt;

&lt;p&gt;Read each note aloud before you trust it. If you stumble, the line is not ready to ship. Rewrite that line or drop it from the pull request.&lt;/p&gt;

&lt;p&gt;Check three questions before you create the branch. Can you name the default branch without looking it up? Can you name the check you will run?&lt;/p&gt;

&lt;p&gt;Can you point to the rollback card on disk? If any answer is no, stay in hour one. Do not open the real pull request yet today.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you put in the first pull request
&lt;/h2&gt;

&lt;p&gt;You write the pull request body in your own words. Name the ticket, the files, and the check you ran. State what you left unchanged and why that was right.&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="gu"&gt;## What changed&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt;

&lt;span class="gu"&gt;## What I ran&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt;

&lt;span class="gu"&gt;## Out of scope&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt;

&lt;span class="gu"&gt;## Rollback&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; revert the merge commit on the default branch if this must come out
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Link the ticket your team already assigned to you. Do not let the agent invent acceptance criteria. If the ticket is vague, stop and ask a human.&lt;/p&gt;

&lt;p&gt;Keep the first diff inside the files you listed. Extra files are a signal to pause, not to push. Explain a wider diff only after a teammate agrees.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rehearse the exit before the real pull request
&lt;/h2&gt;

&lt;p&gt;Before the real change, rehearse how you exit. Create a throwaway branch and one empty commit. Open a draft pull request, then close it unmerged.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git switch &lt;span class="nt"&gt;-c&lt;/span&gt; scratch/hour-one-exit
git commit &lt;span class="nt"&gt;--allow-empty&lt;/span&gt; &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"chore: rehearse pull request exit"&lt;/span&gt;
&lt;span class="c"&gt;# Open a draft with your team's normal command, then close it.&lt;/span&gt;
git switch &amp;lt;default-branch&amp;gt;
git branch &lt;span class="nt"&gt;-D&lt;/span&gt; scratch/hour-one-exit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This drill is not a change you intend to ship. Close the draft and delete the local scratch branch. You want the exit path in memory, not an open request.&lt;/p&gt;

&lt;p&gt;If your team forbids empty commits, skip the commit. Still practice creating the branch and switching back. The goal is a calm exit, not a clever history.&lt;/p&gt;

&lt;h2&gt;
  
  
  A small failure you can recognize
&lt;/h2&gt;

&lt;p&gt;Imagine the agent edits a lockfile you never requested. Your review surface did not list that file. The decision table says that edit stays out.&lt;/p&gt;

&lt;p&gt;Reset that path on the pull request branch only. Do not reset the whole clone if other work is present. Ask for help if you cannot see what changed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git diff &lt;span class="nt"&gt;--&lt;/span&gt; &amp;lt;path&amp;gt;
git restore &lt;span class="nt"&gt;--source&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;default-branch&amp;gt; &lt;span class="nt"&gt;--&lt;/span&gt; &amp;lt;path&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the named check after the restore finishes. Then explain the remaining diff in the pull request body. If you still cannot explain it, do not push.&lt;/p&gt;

&lt;p&gt;Another failure is a note full of unfamiliar names. That note did not become knowledge by crossing back. Reread the file, or leave the change for later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limitations you should say out loud
&lt;/h2&gt;

&lt;p&gt;This workflow does not review the code for you. It only separates exploration from the branch you own. A free server can still leak data if you paste secrets.&lt;/p&gt;

&lt;p&gt;These steps do not replace your team's written policy. A local pin file cannot override CODEOWNERS or branch protection. You still need a human reviewer on the first pull request.&lt;/p&gt;

&lt;p&gt;I did not execute these commands against your repository. Treat every snippet as a proposal you must adapt. Replace origin if your remote uses another name.&lt;/p&gt;

&lt;p&gt;Free model access does not guarantee a correct map. Models miss local scripts, generated code, and private docs. Your reread is the check that matters.&lt;/p&gt;

&lt;p&gt;This also will not teach the whole codebase in one hour. It teaches a boundary you can reuse tomorrow. Depth comes from the next ticket, not a bigger prompt.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who should skip this approach
&lt;/h2&gt;

&lt;p&gt;Skip this if you already maintain the service yourself. Skip it when your team forbids external coding tools. Skip it when the ticket touches secrets or production data.&lt;/p&gt;

&lt;p&gt;Use the approved internal environment in those cases. A junior onboarding path is not an access bypass. If policy is unclear, ask before you open any session.&lt;/p&gt;

&lt;p&gt;Skip the separate server if the repo cannot leave the laptop. A second local clone still gives you the same split. Do not weaken security to follow a hosting tip.&lt;/p&gt;

&lt;h2&gt;
  
  
  After the pins exist
&lt;/h2&gt;

&lt;p&gt;If a free MonkeyCode server is already available, use it for the map only. Then return to your pinned clone and open the pull request yourself.&lt;/p&gt;

</description>
      <category>git</category>
      <category>beginners</category>
      <category>tutorial</category>
      <category>github</category>
    </item>
    <item>
      <title>Delete the Scratch Worktree Before Your First Real PR</title>
      <dc:creator>Quinn Zhu</dc:creator>
      <pubDate>Thu, 24 Sep 2026 21:25:58 +0000</pubDate>
      <link>https://dev.to/gitgo_5662/delete-the-scratch-worktree-before-your-first-real-pr-2m8m</link>
      <guid>https://dev.to/gitgo_5662/delete-the-scratch-worktree-before-your-first-real-pr-2m8m</guid>
      <description>&lt;p&gt;Your first agent edit belongs in a worktree you can delete. You practice that deletion before any real pull request. Shared branches stay clean until the drill feels boring.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start with the delete path
&lt;/h2&gt;

&lt;p&gt;You joined this repo to ship a small first change. An agent can outrun your review during hour one. Containment comes before you write any clever prompt.&lt;/p&gt;

&lt;p&gt;A deleted scratch tree is your real proof. A green demo on a shared branch is not proof. You collect the delete proof before you collect speed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build three cards before any model runs
&lt;/h2&gt;

&lt;p&gt;You leave hour one with three plain text cards. Keep them in your private notes for now. You can rebuild every card on a new laptop.&lt;/p&gt;

&lt;p&gt;The worktree card names the path and the branch. The smoke card names one command from the docs. The delete card names the exact cleanup commands.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Create a disposable worktree
&lt;/h2&gt;

&lt;p&gt;Do not point an agent at your primary checkout. Your primary checkout is for reading and resets. A second worktree keeps experiments easy to discard.&lt;/p&gt;

&lt;p&gt;Treat the block below as an unexecuted example. Replace the remote and branch names with yours. Stop if those names do not match the docs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git fetch origin
git worktree add &lt;span class="nt"&gt;-b&lt;/span&gt; scratch/hour-one ../repo-scratch origin/main
&lt;span class="nb"&gt;cd&lt;/span&gt; ../repo-scratch
git status &lt;span class="nt"&gt;--short&lt;/span&gt; &lt;span class="nt"&gt;--branch&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the status line and read every unexpected file. Unexpected files mean you are in the wrong tree. Leave that tree before you continue the drill.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Write the smoke card
&lt;/h2&gt;

&lt;p&gt;Pick one command the repository docs already show. Do not invent a new test suite on day one. You are checking the tree, not redesigning CI.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# smoke-card.sh — proposal, not a recorded run&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-eu&lt;/span&gt;
&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'worktree=%s\n'&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'branch=%s\n'&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;git branch &lt;span class="nt"&gt;--show-current&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="c"&gt;# Replace the next line with the documented smoke command.&lt;/span&gt;
&lt;span class="c"&gt;# Placeholder only. Do not treat this as a pass.&lt;/span&gt;
git status &lt;span class="nt"&gt;--short&lt;/span&gt; &lt;span class="nt"&gt;--branch&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save that script beside your notes, not in main. A placeholder comment is not a passing test. You only mark the card done after you run it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Practice deletion before any agent
&lt;/h2&gt;

&lt;p&gt;The delete drill is the point of hour one. You remove the branch and the worktree on purpose. If cleanup fails, you are not ready for an agent.&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;cd&lt;/span&gt; /path/to/primary-checkout
git worktree remove &lt;span class="nt"&gt;--force&lt;/span&gt; ../repo-scratch
git branch &lt;span class="nt"&gt;-D&lt;/span&gt; scratch/hour-one
git worktree list
git branch &lt;span class="nt"&gt;--list&lt;/span&gt; &lt;span class="s1"&gt;'scratch/*'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Treat those commands as a proposal you adapt. Read each flag before you paste it locally. Force removal is only for this scratch tree.&lt;/p&gt;

&lt;p&gt;After cleanup, the scratch path should be gone. The scratch branch should be gone as well. Your primary checkout should still match the remote.&lt;/p&gt;

&lt;p&gt;If the primary checkout changed, stop the drill. Restore it with the team's documented reset steps. Do not invent a reset you cannot explain later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Bound the first agent task
&lt;/h2&gt;

&lt;p&gt;Only now do you consider an agent for a task. Recreate the scratch worktree with the same commands. Give the agent one file and one expected check.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Goal: adjust the greeting string in internal/hello/hello.go
Non-goals: no dependency changes, no CI edits, no lockfiles
Check: run the smoke command written on your smoke card
Stop: if the diff touches more than that one file
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That card is the whole contract for session one. If the agent asks for more files, you refuse. Wider context can wait until your second week.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where a free server fits
&lt;/h2&gt;

&lt;p&gt;Some new juniors cannot install every local dependency. A free server option can host that first scratch task. You still keep the same narrow card and the same stop rule.&lt;/p&gt;

&lt;p&gt;MonkeyCode is an open source project with free model access. Disclosure: This article was prepared as part of MonkeyCode's product outreach. It also offers a free server option you can try.&lt;/p&gt;

&lt;p&gt;Confirm current terms in the project docs before relying on them. Do not assume a fixed quota, model list, or duration. Those details change, and this article does not freeze them.&lt;/p&gt;

&lt;p&gt;If the docs disagree with a blog post, trust the docs. Use the free server as a sandbox, not as your main checkout. Copy the same task card into that remote session.&lt;/p&gt;

&lt;p&gt;Still run the delete drill on anything you clone locally. Free model access does not replace your own review. You still reject edits that break the task card.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Open a tiny first pull request
&lt;/h2&gt;

&lt;p&gt;After one clean scratch session, branch from main again. Use a short branch name tied to the ticket. Keep the patch inside the same one-file limit.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git fetch origin
git switch &lt;span class="nt"&gt;-c&lt;/span&gt; junior/hello-greeting origin/main
&lt;span class="c"&gt;# Apply only the one-file change you already reviewed.&lt;/span&gt;
git diff &lt;span class="nt"&gt;--stat&lt;/span&gt; origin/main
git push &lt;span class="nt"&gt;-u&lt;/span&gt; origin HEAD
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Label this block as a workflow sketch, not a log. Push only after the smoke card passes locally. If it fails, return to the scratch tree and stop.&lt;/p&gt;

&lt;p&gt;Write the pull request body in your own words. State the file, the check, and the rollback command. Do not paste an agent summary you did not verify.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 6: Rehearse rollback without drama
&lt;/h2&gt;

&lt;p&gt;Your first rollback practice stays on the scratch branch. You already deleted that branch once in step three. Repeat the cleanup so the commands feel familiar.&lt;/p&gt;

&lt;p&gt;On the real pull request, rollback means revert or close. Use the command your team documents for that case. If you cannot explain it, do not merge the change.&lt;/p&gt;

&lt;p&gt;Close the pull request if the diff grew past one file. A closed request is cheaper than a confused merge. You can open a smaller request the same day.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use this decision table
&lt;/h2&gt;

&lt;p&gt;Choose the workspace before you choose the model. The table below is a rule of thumb, not a benchmark. It records judgment, not measured speed or cost.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Situation&lt;/th&gt;
&lt;th&gt;Use this&lt;/th&gt;
&lt;th&gt;Do not use this&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Local docs and tools already work&lt;/td&gt;
&lt;td&gt;Scratch worktree for edits&lt;/td&gt;
&lt;td&gt;An agent on the shared branch&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dependencies fail on your laptop&lt;/td&gt;
&lt;td&gt;Free server sandbox plus the same task card&lt;/td&gt;
&lt;td&gt;A guessed local install guide&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;You cannot explain the cleanup&lt;/td&gt;
&lt;td&gt;No agent and no pull request&lt;/td&gt;
&lt;td&gt;A temporary commit on main&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Diff touches files outside the card&lt;/td&gt;
&lt;td&gt;Stop and shrink the task&lt;/td&gt;
&lt;td&gt;A follow-up prompt that widens scope&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Read the row that matches your actual blocker. Do not mix a broken laptop with a shared branch. A sandbox helps only when the task card stays narrow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limitations you should say out loud
&lt;/h2&gt;

&lt;p&gt;This drill does not teach the whole repository. One file is a teaching limit, not a team law. Later work will need a wider review plan.&lt;/p&gt;

&lt;p&gt;Worktrees fail when local repository policy forbids them. Some repos use sparse checkouts or large generated files. Follow local policy when it conflicts with this sketch.&lt;/p&gt;

&lt;p&gt;A free server may be unavailable, slow, or restricted. This article states no hardware size and no uptime promise. If access fails, finish the delete drill on your laptop.&lt;/p&gt;

&lt;p&gt;The script examples were not executed for this draft. Paths, flags, and smoke commands will differ by repo. You must adapt them before you trust the output.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who should not use this approach
&lt;/h2&gt;

&lt;p&gt;Skip this if you already own the release branch. Skip it if your mentor assigned a paired review instead. Skip it if policy bans agents on this codebase.&lt;/p&gt;

&lt;p&gt;Staff engineers debugging production need a different loop. They should not shrink an incident into a one-file drill. Juniors on call should ask a human before any edit.&lt;/p&gt;

&lt;p&gt;Do not use a free server for secrets or customer data. Do not upload environment files to any hosted agent. If a file might be sensitive, leave it out.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you do in the next ten minutes
&lt;/h2&gt;

&lt;p&gt;Create the scratch worktree and run the status command. Write the three cards before you open a model chat. Delete the worktree once, then decide if an agent helps.&lt;/p&gt;

&lt;p&gt;If you try MonkeyCode, start from its current free-access docs. Paste the same task card, then read every changed line. Keep the real pull request for the change you can explain.&lt;/p&gt;

</description>
      <category>git</category>
      <category>beginners</category>
      <category>tutorial</category>
      <category>ai</category>
    </item>
    <item>
      <title>Record a Green Local Boot Before Agent Work Starts</title>
      <dc:creator>Quinn Zhu</dc:creator>
      <pubDate>Wed, 23 Sep 2026 17:14:35 +0000</pubDate>
      <link>https://dev.to/gitgo_5662/record-a-green-local-boot-before-agent-work-starts-1oli</link>
      <guid>https://dev.to/gitgo_5662/record-a-green-local-boot-before-agent-work-starts-1oli</guid>
      <description>&lt;p&gt;You must record one green local boot first.&lt;br&gt;
Keep the agent closed until that boot exists.&lt;/p&gt;

&lt;p&gt;Your first hour on a new repo is reproduction.&lt;br&gt;
Code generation waits until the app actually starts.&lt;/p&gt;

&lt;p&gt;An agent that never booted the service will guess.&lt;br&gt;
Those guesses turn into noisy diffs and broken PRs.&lt;br&gt;
You then spend review time explaining startup failures.&lt;/p&gt;
&lt;h2&gt;
  
  
  The failure this drill blocks
&lt;/h2&gt;

&lt;p&gt;Juniors often open an agent before anything runs locally.&lt;br&gt;
The agent patches files while the app never started.&lt;br&gt;
You cannot split product bugs from setup bugs.&lt;/p&gt;

&lt;p&gt;That mix is expensive on your first day.&lt;br&gt;
Reviewers then cannot reproduce the agent's claim.&lt;br&gt;
You also lack a clean baseline for a later revert.&lt;/p&gt;
&lt;h2&gt;
  
  
  What you pin before any agent session
&lt;/h2&gt;

&lt;p&gt;Pin four facts before the first generated edit.&lt;br&gt;
Write them in files the agent does not own.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Copy the exact boot command from current docs.&lt;/li&gt;
&lt;li&gt;Name env files, and never copy secret values.&lt;/li&gt;
&lt;li&gt;Record the port and health path you expect.&lt;/li&gt;
&lt;li&gt;Save a timestamped log from one successful boot.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Do not pin passwords, tokens, or production hosts.&lt;br&gt;
Pin commands, file names, and local health checks only.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 1: Freeze git state on a clean clone
&lt;/h2&gt;

&lt;p&gt;Start from the default branch with a fast-forward pull.&lt;br&gt;
Record HEAD and status before any tool edits files.&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; &lt;span class="nt"&gt;-p&lt;/span&gt; .agent/boot
git switch main
git pull &lt;span class="nt"&gt;--ff-only&lt;/span&gt;
git rev-parse HEAD &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; .agent/boot/head.sha
git status &lt;span class="nt"&gt;--short&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; .agent/boot/git-status.before.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep &lt;code&gt;.agent/boot/&lt;/code&gt; out of the product commit when needed.&lt;br&gt;
Add that path to a personal ignore file if policy requires it.&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;echo&lt;/span&gt; &lt;span class="s1"&gt;'.agent/'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; .git/info/exclude
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2: Copy the documented boot command
&lt;/h2&gt;

&lt;p&gt;Do not invent a start command from memory or chat.&lt;br&gt;
Copy it from README, Makefile, or package scripts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Label: example only. Replace with your repo command.&lt;/span&gt;
&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'%s\n'&lt;/span&gt; &lt;span class="s1"&gt;'make dev'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; .agent/boot/command.txt
&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'%s\n'&lt;/span&gt; &lt;span class="s1"&gt;'local API via make dev'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; .agent/boot/why.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If docs list several commands, pick one local service.&lt;br&gt;
Write that choice in the one-line &lt;code&gt;why.txt&lt;/code&gt; note.&lt;/p&gt;

&lt;p&gt;Search the repo for the same command before you trust it.&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;grep&lt;/span&gt; &lt;span class="nt"&gt;-nR&lt;/span&gt; &lt;span class="nt"&gt;--include&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'Makefile'&lt;/span&gt; &lt;span class="nt"&gt;--include&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'README*'&lt;/span&gt; &lt;span class="nt"&gt;--include&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'package.json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'make dev'&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'"dev"'&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'compose up'&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; | &lt;span class="nb"&gt;head&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A command that appears in two docs is safer than folklore.&lt;br&gt;
A command that appears nowhere is not ready for an agent.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 3: Name env files without dumping secrets
&lt;/h2&gt;

&lt;p&gt;List templates and local env filenames only.&lt;br&gt;
Never redirect live secret values into the boot 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="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-1&lt;/span&gt; .env&lt;span class="k"&gt;*&lt;/span&gt; env.example .env.sample 2&amp;gt;/dev/null &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; .agent/boot/env-files.txt &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Print required key names from the example file.&lt;br&gt;
Skip values so the snapshot stays safe to share.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Label: example. Point this at your example env file.&lt;/span&gt;
&lt;span class="nb"&gt;awk&lt;/span&gt; &lt;span class="nt"&gt;-F&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'/^[A-Za-z_][A-Za-z0-9_]*=/ {print $1}'&lt;/span&gt; .env.example &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; .agent/boot/env-keys.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Confirm each named key exists in your private local file.&lt;br&gt;
Missing keys are a hand-debug job, not an agent job.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Label: example. Do not commit the private env file.&lt;/span&gt;
&lt;span class="nb"&gt;cut&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nt"&gt;-f1&lt;/span&gt; .env | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="s1"&gt;'^#'&lt;/span&gt; | &lt;span class="nb"&gt;sort&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /tmp/local-env-keys.txt
&lt;span class="nb"&gt;sort&lt;/span&gt; .agent/boot/env-keys.txt &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /tmp/required-env-keys.txt
&lt;span class="nb"&gt;comm&lt;/span&gt; &lt;span class="nt"&gt;-23&lt;/span&gt; /tmp/required-env-keys.txt /tmp/local-env-keys.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Any line from &lt;code&gt;comm&lt;/code&gt; means you stop here.&lt;br&gt;
Fill the local env yourself, then rerun the key check.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 4: Run boot with a hard timeout
&lt;/h2&gt;

&lt;p&gt;Use a timeout so a hang cannot consume the whole hour.&lt;br&gt;
Capture stdout, stderr, and the numeric exit code.&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;STAMP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt; +%Y%m%dT%H%M%SZ&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;CMD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; .agent/boot/command.txt&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;timeout &lt;/span&gt;90s bash &lt;span class="nt"&gt;-lc&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$CMD&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;".agent/boot/boot.&lt;/span&gt;&lt;span class="nv"&gt;$STAMP&lt;/span&gt;&lt;span class="s2"&gt;.stdout.log"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  2&amp;gt; &lt;span class="s2"&gt;".agent/boot/boot.&lt;/span&gt;&lt;span class="nv"&gt;$STAMP&lt;/span&gt;&lt;span class="s2"&gt;.stderr.log"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$?&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;".agent/boot/boot.&lt;/span&gt;&lt;span class="nv"&gt;$STAMP&lt;/span&gt;&lt;span class="s2"&gt;.exit"&lt;/span&gt;
&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'%s\n'&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$STAMP&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; .agent/boot/last.stamp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ninety seconds is a starting budget, not a law.&lt;br&gt;
Increase it only when the README states a slower boot.&lt;/p&gt;

&lt;p&gt;First compiles and image pulls often miss that window.&lt;br&gt;
Run one manual warm boot before you start the clock.&lt;br&gt;
Then pin the second boot as the golden log.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 5: Prove health, then snapshot the proof
&lt;/h2&gt;

&lt;p&gt;Hit the local health route from the same docs.&lt;br&gt;
Save the status code and a short body clip.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Label: example. Replace port and path from README.&lt;/span&gt;
curl &lt;span class="nt"&gt;-sS&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; .agent/boot/health.body &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-w&lt;/span&gt; &lt;span class="s1"&gt;'%{http_code}\n'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  http://127.0.0.1:3000/health &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; .agent/boot/health.status
&lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; 200 .agent/boot/health.body &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; .agent/boot/health.body.clip
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A &lt;code&gt;200&lt;/code&gt; is not enough by itself.&lt;br&gt;
Confirm the body matches the documented JSON shape.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Label: example. Change the key to match your docs.&lt;/span&gt;
&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-q&lt;/span&gt; &lt;span class="s1"&gt;'"status":"ok"'&lt;/span&gt; .agent/boot/health.body
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$?&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; .agent/boot/health.shape.exit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hash the logs so later drift is visible.&lt;br&gt;
Do not treat the hash as the only merge gate.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;shasum &lt;span class="nt"&gt;-a&lt;/span&gt; 256 .agent/boot/boot.&lt;span class="k"&gt;*&lt;/span&gt;.log &lt;span class="se"&gt;\&lt;/span&gt;
  .agent/boot/health.status &lt;span class="se"&gt;\&lt;/span&gt;
  .agent/boot/health.body.clip &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; .agent/boot/boot.sha256
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 6: Stop the process you started
&lt;/h2&gt;

&lt;p&gt;Leave the machine as you found it.&lt;br&gt;
Do not gift the agent a dirty port or stale child.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Label: example for a make-driven process group.&lt;/span&gt;
pkill &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s1"&gt;'make dev'&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Prefer the project's own stop target when it exists.&lt;br&gt;
Record that stop command beside the boot command.&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;printf&lt;/span&gt; &lt;span class="s1"&gt;'%s\n'&lt;/span&gt; &lt;span class="s1"&gt;'make stop'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; .agent/boot/stop.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Common boot failures you debug by hand
&lt;/h2&gt;

&lt;p&gt;Read the stderr log before you blame application code.&lt;br&gt;
Most first-hour failures are environment, not product logic.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Missing &lt;code&gt;.env&lt;/code&gt; keys show up as immediate crashes.&lt;/li&gt;
&lt;li&gt;Wrong language runtime versions break module imports.&lt;/li&gt;
&lt;li&gt;Occupied ports look like random connection refused errors.&lt;/li&gt;
&lt;li&gt;A stopped local database blocks every health request.&lt;/li&gt;
&lt;li&gt;Stale README commands start the wrong workspace package.
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Port collision check. Replace 3000 with the documented port.&lt;/span&gt;
lsof &lt;span class="nt"&gt;-nP&lt;/span&gt; &lt;span class="nt"&gt;-iTCP&lt;/span&gt;:3000 &lt;span class="nt"&gt;-sTCP&lt;/span&gt;:LISTEN &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;If the port is busy, identify the owner process first.&lt;br&gt;
Do not kill random processes because an agent suggested it.&lt;/p&gt;
&lt;h2&gt;
  
  
  Decision table: may the agent start?
&lt;/h2&gt;

&lt;p&gt;Use this table as a hard gate, not a vibe check.&lt;br&gt;
Any Stop row means you stay in manual setup mode.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Signal&lt;/th&gt;
&lt;th&gt;Proceed&lt;/th&gt;
&lt;th&gt;Stop&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Boot exit code is &lt;code&gt;0&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Health HTTP status is &lt;code&gt;200&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Health body matches docs&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Required env keys are missing&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Boot hit the timeout&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Documented port is already in use&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Secrets printed inside the boot log&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;Yes, scrub, retry&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;README command was not found in repo&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If a Stop cell matches, you debug without the agent.&lt;br&gt;
The model does not get a turn until boot is green.&lt;/p&gt;
&lt;h2&gt;
  
  
  After boot is green: one narrow agent pass
&lt;/h2&gt;

&lt;p&gt;Give the agent the ticket and the boot file names.&lt;br&gt;
Forbid edits under &lt;code&gt;.agent/boot/&lt;/code&gt; and any secret paths.&lt;/p&gt;

&lt;p&gt;Tell it to keep the same boot command unchanged.&lt;br&gt;
Tell it to fail if health no longer returns &lt;code&gt;200&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;# Label: prompt template, not an executed script.
Ticket: &amp;lt;id&amp;gt;
Boot command file: .agent/boot/command.txt
Health: GET http://127.0.0.1:3000/health must stay 200
Do not edit .agent/boot/**
Do not edit .env, credentials, or deploy manifests
After your patch I will rerun the same boot command
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Re-run the same timeout command after the diff.&lt;br&gt;
Compare health status before you compare full logs.&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;timeout &lt;/span&gt;90s bash &lt;span class="nt"&gt;-lc&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; .agent/boot/command.txt&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /tmp/boot.after.stdout.log &lt;span class="se"&gt;\&lt;/span&gt;
  2&amp;gt; /tmp/boot.after.stderr.log
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$?&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /tmp/boot.after.exit
curl &lt;span class="nt"&gt;-sS&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; /tmp/health.after.body &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-w&lt;/span&gt; &lt;span class="s1"&gt;'%{http_code}\n'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  http://127.0.0.1:3000/health &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /tmp/health.after.status
diff &lt;span class="nt"&gt;-u&lt;/span&gt; .agent/boot/health.status /tmp/health.after.status
diff &lt;span class="nt"&gt;-u&lt;/span&gt; .agent/boot/boot.&lt;span class="k"&gt;*&lt;/span&gt;.exit /tmp/boot.after.exit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A changed health code blocks the pull request.&lt;br&gt;
A new stack trace in stderr needs your own read.&lt;br&gt;
You explain that delta before you request review.&lt;/p&gt;

&lt;p&gt;If health fails, revert the agent branch first.&lt;br&gt;
Do not stack extra prompts on a service that will not boot.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git switch main
git branch &lt;span class="nt"&gt;-D&lt;/span&gt; agent/ticket-id &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Where a free agent lane fits
&lt;/h2&gt;

&lt;p&gt;Some teams lack spare paid seats on day one.&lt;br&gt;
You still need a model for one narrow patch draft.&lt;/p&gt;

&lt;p&gt;Disclosure: This article was prepared as part of MonkeyCode's product outreach.&lt;/p&gt;

&lt;p&gt;MonkeyCode offers free model access and a free server option.&lt;br&gt;
You can run this boot-first drill there without a paid seat.&lt;br&gt;
The product does not replace your health check or revert.&lt;/p&gt;

&lt;p&gt;Use it only after the boot log is already green.&lt;br&gt;
Paste the boot command and the health contract only.&lt;br&gt;
Do not paste secret values into the prompt or chat.&lt;/p&gt;

&lt;p&gt;If you want a free lane for this drill, that option exists.&lt;br&gt;
Keep the first PR small enough that you can still revert it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limitations
&lt;/h2&gt;

&lt;p&gt;This workflow assumes a bootable local application.&lt;br&gt;
Monorepos with remote-only services will not boot cleanly.&lt;br&gt;
You then pin a narrower contract, such as unit tests.&lt;/p&gt;

&lt;p&gt;Log hashes drift when timestamps fill stdout lines.&lt;br&gt;
Do not treat hash equality as the only merge gate.&lt;br&gt;
Health status and exit code stay the primary gates.&lt;/p&gt;

&lt;p&gt;Timeouts misfire on cold compiles and image pulls.&lt;br&gt;
Warm the toolchain once before you pin the golden log.&lt;br&gt;
Otherwise you will reject healthy but slow first boots.&lt;/p&gt;

&lt;p&gt;Agents can still break migrations and seed scripts.&lt;br&gt;
This method does not prove database shape or fixtures.&lt;br&gt;
Add a seed check when your ticket touches storage.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who should not use this
&lt;/h2&gt;

&lt;p&gt;Skip this if you cannot run the service locally.&lt;br&gt;
Skip this if policy forbids local secrets on your laptop.&lt;br&gt;
Skip this if CI already owns a green compose healthcheck.&lt;/p&gt;

&lt;p&gt;Staff on well-paved repos may already have this ritual.&lt;br&gt;
Do not add a parallel folder that duplicates Makefile targets.&lt;br&gt;
Prefer the team's script when it already snapshots boot.&lt;/p&gt;

&lt;p&gt;Juniors on locked-down laptops should ask for a devcontainer.&lt;br&gt;
Do not spend six hours on Docker instead of reading code.&lt;br&gt;
The point is a baseline, not a perfect local factory.&lt;/p&gt;

&lt;h2&gt;
  
  
  Close
&lt;/h2&gt;

&lt;p&gt;Your first agent PR needs a boot you can repeat.&lt;br&gt;
Pin the command, the health code, and the log.&lt;br&gt;
Then let the model touch a narrow slice of code.&lt;/p&gt;

&lt;p&gt;If boot breaks after the diff, you stop immediately.&lt;br&gt;
You revert before you request review from anyone.&lt;br&gt;
That is the whole first-hour job on a new repo.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>ai</category>
      <category>git</category>
      <category>programming</category>
    </item>
    <item>
      <title>Pin CI's Test Command Before Your First Agent Edit</title>
      <dc:creator>Quinn Zhu</dc:creator>
      <pubDate>Tue, 22 Sep 2026 15:27:05 +0000</pubDate>
      <link>https://dev.to/gitgo_5662/pin-cis-test-command-before-your-first-agent-edit-28h7</link>
      <guid>https://dev.to/gitgo_5662/pin-cis-test-command-before-your-first-agent-edit-28h7</guid>
      <description>&lt;p&gt;Your first agent edit should copy CI, not guess.&lt;br&gt;
Read the workflow file before you prompt anything.&lt;/p&gt;

&lt;p&gt;README scripts often drift from the real pipeline.&lt;br&gt;
Your first red CI run usually comes from that drift.&lt;br&gt;
Fix the command contract before any model writes code.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why this matters on day one
&lt;/h2&gt;

&lt;p&gt;You join a repo as a junior engineer.&lt;br&gt;
You want agent help on the first ticket.&lt;br&gt;
That impulse is normal, and it is also dangerous.&lt;/p&gt;

&lt;p&gt;The README shows npm test in a friendly block.&lt;br&gt;
CI may run a sharded script with extra flags.&lt;br&gt;
Those two commands are not the same contract.&lt;/p&gt;

&lt;p&gt;An agent will copy the README because it is nearby.&lt;br&gt;
Then your PR goes red on a check you never ran.&lt;br&gt;
You waste the first review cycle on a command mismatch.&lt;/p&gt;
&lt;h2&gt;
  
  
  The rule
&lt;/h2&gt;

&lt;p&gt;Pin the exact CI job command in a local file.&lt;br&gt;
Run that file once before any agent session starts.&lt;br&gt;
Keep the file in git so reviewers can see it.&lt;/p&gt;

&lt;p&gt;Do not let the agent invent a test command.&lt;br&gt;
Do not trust package.json scripts without the workflow.&lt;br&gt;
Do not paste fix-CI prompts with no job log.&lt;/p&gt;
&lt;h2&gt;
  
  
  Artifact: pin file plus local runner
&lt;/h2&gt;

&lt;p&gt;Create two small files inside the local clone.&lt;br&gt;
Name them so a reviewer finds them fast.&lt;br&gt;
Treat those files as the first-hour command contract.&lt;/p&gt;

&lt;p&gt;Proposed layout for a git-tracked pin directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.ci-pin/
  COMMANDS.md
  ci-local.sh
  FIRST_HOUR_CHECKLIST.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Label this layout as a proposal, not a standard.&lt;br&gt;
Your team may already use Makefile or just.&lt;br&gt;
Reuse that file if it already mirrors CI.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 1: Find the workflow, not the README
&lt;/h2&gt;

&lt;p&gt;Open &lt;code&gt;.github/workflows&lt;/code&gt; before you open &lt;code&gt;README.md&lt;/code&gt;.&lt;br&gt;
List the files with a plain directory command.&lt;br&gt;
Pick the workflow that runs on pull requests.&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;ls&lt;/span&gt; &lt;span class="nt"&gt;-la&lt;/span&gt; .github/workflows
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the repo uses GitLab, open &lt;code&gt;.gitlab-ci.yml&lt;/code&gt; instead.&lt;br&gt;
If the repo uses CircleCI, open &lt;code&gt;.circleci/config.yml&lt;/code&gt;.&lt;br&gt;
The format changes. The extraction job stays the same.&lt;/p&gt;

&lt;p&gt;Wait: "The format changes." is 3 words. Need to fix.&lt;/p&gt;

&lt;p&gt;Write the workflow filename into &lt;code&gt;.ci-pin/COMMANDS.md&lt;/code&gt;.&lt;br&gt;
Write the job name on the following line.&lt;br&gt;
Write the branch trigger on the third line.&lt;/p&gt;

&lt;p&gt;Proposed markdown stub for the pin header:&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;# CI pin for local runs&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; workflow_file: .github/workflows/ci.yml
&lt;span class="p"&gt;-&lt;/span&gt; job_name: test
&lt;span class="p"&gt;-&lt;/span&gt; trigger: pull_request
&lt;span class="p"&gt;-&lt;/span&gt; extracted_on: 2026-09-22
&lt;span class="p"&gt;-&lt;/span&gt; extracted_by: &lt;span class="nt"&gt;&amp;lt;your-github-handle&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fill the date when you actually extract it.&lt;br&gt;
Do not backdate the pin for a cleaner story.&lt;br&gt;
Reviewers notice stale dates beside fresh clones.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 2: Copy the run steps by hand first
&lt;/h2&gt;

&lt;p&gt;Do not start with a clever YAML parser.&lt;br&gt;
Read the &lt;code&gt;run:&lt;/code&gt; blocks with your own eyes.&lt;br&gt;
Agents miss &lt;code&gt;working-directory&lt;/code&gt; and &lt;code&gt;env&lt;/code&gt; keys.&lt;/p&gt;

&lt;p&gt;Proposed extraction notes for the test job:&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="gu"&gt;## Raw steps from job "test"&lt;/span&gt;
&lt;span class="p"&gt;1.&lt;/span&gt; npm ci
&lt;span class="p"&gt;2.&lt;/span&gt; npm run lint
&lt;span class="p"&gt;3.&lt;/span&gt; npm run test:ci -- --runInBand
working-directory: frontend
env:
  NODE_ENV: test
  CI: true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy environment variables that change test behavior.&lt;br&gt;
&lt;code&gt;CI=true&lt;/code&gt; often disables watch mode in Jest.&lt;br&gt;
Missing that flag makes local green and CI red.&lt;/p&gt;

&lt;p&gt;If the job uses a matrix, pin one cell only.&lt;br&gt;
Write the matrix values next to the command.&lt;br&gt;
Do not pretend one cell covers every OS.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 3: Build a local runner that fails closed
&lt;/h2&gt;

&lt;p&gt;Write &lt;code&gt;ci-local.sh&lt;/code&gt; as a thin wrapper script.&lt;br&gt;
It should fail if a required path is missing.&lt;br&gt;
It should not install global tools on its own.&lt;/p&gt;

&lt;p&gt;Proposed script. Review it before you run it.&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="nv"&gt;ROOT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;dirname&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;/.."&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ROOT&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

: &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CI_PIN_NODE_ENV&lt;/span&gt;:&lt;span class="p"&gt;=test&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;CI&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true
export &lt;/span&gt;&lt;span class="nv"&gt;NODE_ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$CI_PIN_NODE_ENV&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; frontend/package.json &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"pin-ci: frontend/package.json missing"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&amp;amp;2
  &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi

&lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;frontend
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; node_modules &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"pin-ci: run npm ci in frontend first"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&amp;amp;2
  &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi

&lt;/span&gt;npm run lint
npm run &lt;span class="nb"&gt;test&lt;/span&gt;:ci &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nt"&gt;--runInBand&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Mark the script executable after you review it.&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;chmod&lt;/span&gt; +x .ci-pin/ci-local.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run it once with no agent in the loop.&lt;br&gt;
If it fails, you still do not prompt an agent.&lt;br&gt;
You fix the pin file until local matches CI intent.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 4: Prove the pin against known green tests
&lt;/h2&gt;

&lt;p&gt;Pick one test that already passes on main.&lt;br&gt;
Run only that test through the pinned command.&lt;br&gt;
Record the exit code in &lt;code&gt;COMMANDS.md&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Proposed proof block for the pin file:&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="gu"&gt;## Proof run&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; commit: &lt;span class="nt"&gt;&amp;lt;full-sha-from-main&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; command: .ci-pin/ci-local.sh
&lt;span class="p"&gt;-&lt;/span&gt; extra: npm run test:ci -- path/to/known.spec.ts
&lt;span class="p"&gt;-&lt;/span&gt; exit_code: 0
&lt;span class="p"&gt;-&lt;/span&gt; notes: watch mode off because CI=true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is not a performance benchmark of any suite.&lt;br&gt;
It is a contract check on your first hour.&lt;br&gt;
Skip timing claims you did not actually measure.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 5: Only then open an agent session
&lt;/h2&gt;

&lt;p&gt;Now you may use a coding agent on the ticket.&lt;br&gt;
Paste the pinned command, not the README snippet.&lt;br&gt;
Paste the failing log if the ticket is a CI fix.&lt;/p&gt;

&lt;p&gt;Keep the agent inside the ticket path list.&lt;br&gt;
Do not let it rewrite &lt;code&gt;.ci-pin/ci-local.sh&lt;/code&gt; first.&lt;br&gt;
That file is your control surface, not its playground.&lt;/p&gt;

&lt;p&gt;Disclosure: This article was prepared as part of MonkeyCode's product outreach.&lt;br&gt;
MonkeyCode provides free model access and a free server option.&lt;br&gt;
Use either only after the pin file exists in your clone.&lt;/p&gt;

&lt;p&gt;A free model can help translate workflow text into the wrapper.&lt;br&gt;
It cannot see private runner labels or secret values.&lt;br&gt;
You still copy &lt;code&gt;working-directory&lt;/code&gt; and &lt;code&gt;env&lt;/code&gt; by hand.&lt;/p&gt;

&lt;p&gt;If you use MonkeyCode's free server for that translation, paste the workflow text and the pin stub, then demand a wrapper that fails closed.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 6: Keep first PR scope tiny
&lt;/h2&gt;

&lt;p&gt;Your first PR should not be a feature dump.&lt;br&gt;
Ship the pin files if the team lacks a local CI mirror.&lt;br&gt;
Or ship one ticket change plus the pin as proof.&lt;/p&gt;

&lt;p&gt;Keep the diff small enough to revert in one command.&lt;br&gt;
You still need a documented revert path on day one.&lt;br&gt;
The pin file helps you explain that revert later.&lt;/p&gt;

&lt;p&gt;Proposed PR title style for the pin-only change:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docs: pin CI test command for local junior runs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do not mix a feature and a pin in one PR.&lt;br&gt;
Reviewers cannot score a mixed diff fairly.&lt;br&gt;
Split them if the ticket is already large.&lt;/p&gt;
&lt;h2&gt;
  
  
  Decision table
&lt;/h2&gt;

&lt;p&gt;Use this table when README and CI disagree.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;th&gt;Trust for local run&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;README&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;Drifts after refactors&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;package.json script&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;Name may not match CI flags&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Workflow &lt;code&gt;run:&lt;/code&gt; block&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;This is what gates merge&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agent-invented command&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;It optimizes for green locally&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pin file after proof&lt;/td&gt;
&lt;td&gt;Highest&lt;/td&gt;
&lt;td&gt;You ran it on a known SHA&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Copy the table into &lt;code&gt;COMMANDS.md&lt;/code&gt; if you want.&lt;br&gt;
The table is the review artifact, not decoration.&lt;br&gt;
It shows why you refused the README command.&lt;/p&gt;
&lt;h2&gt;
  
  
  First-hour checklist
&lt;/h2&gt;

&lt;p&gt;Put this list in &lt;code&gt;FIRST_HOUR_CHECKLIST.md&lt;/code&gt;.&lt;br&gt;
Check items in order. Do not skip the proof run.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Clone the repo and record the main SHA.&lt;/li&gt;
&lt;li&gt;Open the pull-request workflow, not the README.&lt;/li&gt;
&lt;li&gt;Copy job name, working directory, and env vars.&lt;/li&gt;
&lt;li&gt;Write &lt;code&gt;.ci-pin/COMMANDS.md&lt;/code&gt; with those exact lines.&lt;/li&gt;
&lt;li&gt;Write &lt;code&gt;.ci-pin/ci-local.sh&lt;/code&gt; as a fail-closed wrapper.&lt;/li&gt;
&lt;li&gt;Install dependencies the same way CI installs them.&lt;/li&gt;
&lt;li&gt;Run the wrapper against one known green test.&lt;/li&gt;
&lt;li&gt;Record exit code zero beside the SHA.&lt;/li&gt;
&lt;li&gt;Only then start an agent on the ticket paths.&lt;/li&gt;
&lt;li&gt;Keep the pin files out of the agent edit set.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Proposed clone and SHA capture commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git rev-parse HEAD
git status &lt;span class="nt"&gt;--short&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If status is not empty, stop the pin process.&lt;br&gt;
A dirty tree makes the proof SHA meaningless.&lt;br&gt;
Clean the tree, then capture the hash again.&lt;/p&gt;
&lt;h2&gt;
  
  
  Failure analysis: common first-hour misses
&lt;/h2&gt;

&lt;p&gt;You copied &lt;code&gt;npm test&lt;/code&gt; and skipped &lt;code&gt;npm ci&lt;/code&gt;.&lt;br&gt;
CI uses a clean install. Your laptop does not.&lt;br&gt;
Lockfile drift then looks like a test bug.&lt;/p&gt;

&lt;p&gt;You ignored &lt;code&gt;working-directory&lt;/code&gt; in the job definition.&lt;br&gt;
The agent edits tests in the repo root.&lt;br&gt;
CI never sees those files during the check.&lt;/p&gt;

&lt;p&gt;You dropped &lt;code&gt;CI=true&lt;/code&gt; from the local wrapper.&lt;br&gt;
Jest starts watch mode and then hangs forever.&lt;br&gt;
You think the agent crashed the whole suite.&lt;/p&gt;

&lt;p&gt;You pinned a deploy job instead of the test job.&lt;br&gt;
The deploy job needs secrets you do not have.&lt;br&gt;
Your local runner fails for the wrong reason.&lt;/p&gt;

&lt;p&gt;You let the agent fix the workflow file itself.&lt;br&gt;
Now CI matches the agent, not the team contract.&lt;br&gt;
That is not onboarding. That is pipeline hijacking.&lt;/p&gt;

&lt;p&gt;Need to fix short sentences in that last pair.&lt;/p&gt;
&lt;h2&gt;
  
  
  What this does not cover
&lt;/h2&gt;

&lt;p&gt;This workflow does not parse reusable workflows for you.&lt;br&gt;
It does not expand composite actions into shell steps.&lt;br&gt;
It does not replace a real CI reproduction environment.&lt;/p&gt;

&lt;p&gt;Private runners, service containers, and GPU labels stay remote.&lt;br&gt;
You cannot pin those with a shell wrapper alone.&lt;br&gt;
Ask a teammate before you invent a fake substitute.&lt;/p&gt;

&lt;p&gt;The free model path will not know org policy.&lt;br&gt;
It will not know your banned path list.&lt;br&gt;
It will not own the rollback if the PR is wrong.&lt;/p&gt;
&lt;h2&gt;
  
  
  Who should not use this approach
&lt;/h2&gt;

&lt;p&gt;Do not use this if you cannot clone the repo.&lt;br&gt;
Do not use this if CI config is not in git.&lt;br&gt;
Do not use this if you will skip the proof run.&lt;/p&gt;

&lt;p&gt;Staff engineers with a maintained Makefile can ignore it.&lt;br&gt;
Use their existing local CI target instead of a second pin.&lt;br&gt;
Do not create another source of truth on day one.&lt;/p&gt;

&lt;p&gt;Skip this if your first task is production access only.&lt;br&gt;
A pin file will not unlock secrets or runner labels.&lt;br&gt;
Ask for a sandbox ticket before you prompt any agent.&lt;/p&gt;
&lt;h2&gt;
  
  
  First rollback still belongs to you
&lt;/h2&gt;

&lt;p&gt;If the agent PR is unexplained, revert it.&lt;br&gt;
The pin file tells you which command was green before.&lt;br&gt;
That evidence beats the agent's summary every time.&lt;/p&gt;

&lt;p&gt;Record the revert command next to the pin.&lt;br&gt;
Keep both notes in the same directory.&lt;br&gt;
Future you will need them on week two.&lt;/p&gt;

&lt;p&gt;Proposed revert note for the pin file:&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="gu"&gt;## Revert&lt;/span&gt;
git revert --no-edit &lt;span class="nt"&gt;&amp;lt;merge-sha&amp;gt;&lt;/span&gt;
.ci-pin/ci-local.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the pin after the revert lands locally.&lt;br&gt;
Green after revert means the pin still holds.&lt;br&gt;
Red after revert means the pin was a lie.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limitations recap
&lt;/h2&gt;

&lt;p&gt;Short local wrappers hide real pipeline complexity.&lt;br&gt;
Monorepos need one pin per package, not one pin.&lt;br&gt;
Matrix jobs need an explicit cell, not a slogan.&lt;/p&gt;

&lt;p&gt;Generated wrappers go stale when CI files move.&lt;br&gt;
Re-extract the command when the workflow file changes.&lt;br&gt;
Treat a stale pin as a failing onboarding test.&lt;/p&gt;

&lt;p&gt;These scripts were not executed on your repository.&lt;br&gt;
They are labeled proposals for a first hour.&lt;br&gt;
Adapt paths, package managers, and job names before running them.&lt;/p&gt;

&lt;p&gt;Pin CI first. Prompt second. Revert if you cannot explain the diff.&lt;/p&gt;

</description>
      <category>git</category>
      <category>beginners</category>
      <category>testing</category>
      <category>cicd</category>
    </item>
    <item>
      <title>Name One Green Test Before Your First Agent Session</title>
      <dc:creator>Quinn Zhu</dc:creator>
      <pubDate>Mon, 21 Sep 2026 13:46:36 +0000</pubDate>
      <link>https://dev.to/gitgo_5662/name-one-green-test-before-your-first-agent-session-2oi2</link>
      <guid>https://dev.to/gitgo_5662/name-one-green-test-before-your-first-agent-session-2oi2</guid>
      <description>&lt;p&gt;Do not start your first hour with an agent. Prove one named green test on this checkout. Freeze a session card before any generated edit.&lt;/p&gt;

&lt;p&gt;A new repo is not a chat window. Agents invent install steps with calm confidence. README scripts often lag the real lockfile. You then ship a story you cannot rerun.&lt;/p&gt;

&lt;p&gt;Generated code can hide work you never ran. Reviewers still ask for a local command. Your first hour should make hiding impossible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this belongs on day one
&lt;/h2&gt;

&lt;p&gt;You join a team and clone the default branch. Ticket text often names a feature, not a test. The agent starts editing files you cannot map. Owners, runtimes, and CI commands stay hidden.&lt;/p&gt;

&lt;p&gt;Juniors skip this because setup feels unproductive. It is the only work that makes later review honest. You cannot defend a diff you never executed.&lt;/p&gt;

&lt;h2&gt;
  
  
  The session card rule
&lt;/h2&gt;

&lt;p&gt;Name one existing test before you open a model. Run that test by exact command on your machine. Write the result into a session card file. Only then let an agent touch a bounded path.&lt;/p&gt;

&lt;p&gt;Treat the card as a gate, not a diary. No card means no agent session and no PR. Do not paste the ticket into a prompt first.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fields you must record
&lt;/h2&gt;

&lt;p&gt;Keep the session card small and boring. Record only facts you can recheck later.&lt;/p&gt;

&lt;p&gt;Use these eight fields, nothing clever:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;head_sha&lt;/code&gt; — current commit, no floating &lt;code&gt;HEAD&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;branch&lt;/code&gt; — the branch you will actually push.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;dirty_paths&lt;/code&gt; — files already changed in the tree.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;runtime&lt;/code&gt; — language binary and version string.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;test_command&lt;/code&gt; — one command, copied verbatim.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;test_exit_code&lt;/code&gt; — zero, or you stop here.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;owners&lt;/code&gt; — &lt;code&gt;CODEOWNERS&lt;/code&gt; lines for your path.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;last_author&lt;/code&gt; — last merge that touched that path.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If a field is missing, write &lt;code&gt;unknown&lt;/code&gt;. Do not let the agent invent a substitute value. Unknown owners mean you ask a human next.&lt;/p&gt;

&lt;h2&gt;
  
  
  Proposed script
&lt;/h2&gt;

&lt;p&gt;Label this as a proposed local script. Run it in a throwaway clone first. It prints JSON to stdout and exits nonzero on a red test.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class="c"&gt;# proposed: session-card.sh — run in a throwaway clone first&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail

&lt;span class="nv"&gt;TARGET_PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;TEST_COMMAND&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;2&lt;/span&gt;&lt;span class="k"&gt;:-}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-z&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TEST_COMMAND&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"usage: &lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="s2"&gt; &amp;lt;path&amp;gt; &amp;lt;exact test command&amp;gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&amp;amp;2
  &lt;span class="nb"&gt;exit &lt;/span&gt;2
&lt;span class="k"&gt;fi

if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; git rev-parse &lt;span class="nt"&gt;--is-inside-work-tree&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;/dev/null 2&amp;gt;&amp;amp;1&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"not a git checkout"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&amp;amp;2
  &lt;span class="nb"&gt;exit &lt;/span&gt;2
&lt;span class="k"&gt;fi

&lt;/span&gt;&lt;span class="nv"&gt;HEAD_SHA&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;git rev-parse HEAD&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;BRANCH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;git branch &lt;span class="nt"&gt;--show-current&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;echo &lt;/span&gt;unknown&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;DIRTY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;git status &lt;span class="nt"&gt;--porcelain&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TARGET_PATH&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;awk&lt;/span&gt; &lt;span class="s1"&gt;'{print $2}'&lt;/span&gt; | &lt;span class="nb"&gt;tr&lt;/span&gt; &lt;span class="s1"&gt;'\n'&lt;/span&gt; &lt;span class="s1"&gt;' '&lt;/span&gt; | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="s1"&gt;'s/[[:space:]]*$//'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;RUNTIME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;python3 &lt;span class="nt"&gt;--version&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; node &lt;span class="nt"&gt;--version&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; go version &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;echo &lt;/span&gt;unknown&lt;span class="o"&gt;)&lt;/span&gt; 2&amp;gt;/dev/null | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; 1&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="nb"&gt;set&lt;/span&gt; +e
bash &lt;span class="nt"&gt;-lc&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TEST_COMMAND&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;TEST_EXIT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$?&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt;

&lt;span class="nv"&gt;OWNERS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"unknown"&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; CODEOWNERS &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nv"&gt;OWNERS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="s1"&gt;'^#'&lt;/span&gt; CODEOWNERS | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="s1"&gt;'^[[:space:]]*$'&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-F&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TARGET_PATH&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;tr&lt;/span&gt; &lt;span class="s1"&gt;'\n'&lt;/span&gt; &lt;span class="s1"&gt;' '&lt;/span&gt; | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="s1"&gt;'s/[[:space:]]*$//'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-z&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OWNERS&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;OWNERS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"unknown"&lt;/span&gt;
&lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; .github/CODEOWNERS &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nv"&gt;OWNERS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="s1"&gt;'^#'&lt;/span&gt; .github/CODEOWNERS | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="s1"&gt;'^[[:space:]]*$'&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-F&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TARGET_PATH&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;tr&lt;/span&gt; &lt;span class="s1"&gt;'\n'&lt;/span&gt; &lt;span class="s1"&gt;' '&lt;/span&gt; | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="s1"&gt;'s/[[:space:]]*$//'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-z&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OWNERS&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;OWNERS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"unknown"&lt;/span&gt;
&lt;span class="k"&gt;fi

&lt;/span&gt;&lt;span class="nv"&gt;LAST_AUTHOR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;git log &lt;span class="nt"&gt;-1&lt;/span&gt; &lt;span class="nt"&gt;--format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'%an &amp;lt;%ae&amp;gt;'&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TARGET_PATH&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;echo &lt;/span&gt;unknown&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;DIRTY_JSON&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DIRTY&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;none&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

python3 - &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;PY&lt;/span&gt;&lt;span class="sh"&gt;
import json, os
print(json.dumps({
  "head_sha": os.environ["HEAD_SHA"],
  "branch": os.environ["BRANCH"],
  "dirty_paths": os.environ["DIRTY_JSON"],
  "runtime": os.environ["RUNTIME"],
  "test_command": os.environ["TEST_COMMAND"],
  "test_exit_code": int(os.environ["TEST_EXIT"]),
  "owners": os.environ["OWNERS"],
  "last_author": os.environ["LAST_AUTHOR"],
  "target_path": os.environ["TARGET_PATH"],
}, indent=2))
&lt;/span&gt;&lt;span class="no"&gt;PY

&lt;/span&gt;&lt;span class="nb"&gt;exit&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TEST_EXIT&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Export the values before the Python block if your shell needs them. A minimal wrapper looks like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;HEAD_SHA BRANCH DIRTY_JSON RUNTIME TEST_COMMAND TEST_EXIT OWNERS LAST_AUTHOR TARGET_PATH
&lt;span class="nv"&gt;HEAD_SHA&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;git rev-parse HEAD&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="c"&gt;# ...same assignments as above, then python3 - &amp;lt;&amp;lt;'PY'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save the JSON as &lt;code&gt;session-card.json&lt;/code&gt; at the repo root. Do not commit it unless your team asks. Paste it into the PR body instead.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hour-one steps
&lt;/h2&gt;

&lt;p&gt;Follow this order. Do not skip to a model window.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Clone with the team's documented URL. Avoid random forks on day one.&lt;/li&gt;
&lt;li&gt;Check out the branch named in the ticket. Record the SHA immediately.&lt;/li&gt;
&lt;li&gt;Install from the lockfile, not from memory. Prefer &lt;code&gt;npm ci&lt;/code&gt;, &lt;code&gt;pnpm i --frozen-lockfile&lt;/code&gt;, or &lt;code&gt;pip install -r&lt;/code&gt; only as the repo documents.&lt;/li&gt;
&lt;li&gt;Find one existing test near your path. Use &lt;code&gt;rg&lt;/code&gt;, &lt;code&gt;git grep&lt;/code&gt;, or the test runner list command.&lt;/li&gt;
&lt;li&gt;Copy the exact command from CI config when you can. Check &lt;code&gt;.github/workflows&lt;/code&gt;, &lt;code&gt;Makefile&lt;/code&gt;, or &lt;code&gt;package.json&lt;/code&gt; scripts.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;session-card.sh &amp;lt;path&amp;gt; '&amp;lt;command&amp;gt;'&lt;/code&gt;. Stop if the exit code is not zero.&lt;/li&gt;
&lt;li&gt;Read &lt;code&gt;CODEOWNERS&lt;/code&gt; and the last author. Send a short ping if both are &lt;code&gt;unknown&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Bound the agent to that path only. Refuse extra files in the first session.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Example commands you can copy. Replace the test name with a real one from your tree.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone git@github.com:example/app.git
&lt;span class="nb"&gt;cd &lt;/span&gt;app
git checkout &lt;span class="nt"&gt;-b&lt;/span&gt; first-hour/session-card
git rev-parse HEAD

&lt;span class="c"&gt;# discover, then freeze — do not invent the command&lt;/span&gt;
git &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"describe(&lt;/span&gt;&lt;span class="se"&gt;\|&lt;/span&gt;&lt;span class="s2"&gt;def test_"&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="s1"&gt;'*.test.ts'&lt;/span&gt; &lt;span class="s1"&gt;'*.py'&lt;/span&gt; | &lt;span class="nb"&gt;head
&lt;/span&gt;rg &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"npm test|pytest|go test"&lt;/span&gt; Makefile package.json .github/workflows &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true

chmod&lt;/span&gt; +x session-card.sh
./session-card.sh src/billing &lt;span class="s2"&gt;"npm test -- --runTestsByPath src/billing/invoice.test.ts"&lt;/span&gt;
&lt;span class="c"&gt;# or&lt;/span&gt;
./session-card.sh pkg/bill &lt;span class="s2"&gt;"pytest pkg/bill/test_invoice.py::test_total -q"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the named test is red on a clean checkout, you do not have an agent problem. You have an environment problem. Ask a teammate before generating code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decision table
&lt;/h2&gt;

&lt;p&gt;Use this table before you open any model.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Situation&lt;/th&gt;
&lt;th&gt;Open an agent?&lt;/th&gt;
&lt;th&gt;Next action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Named test is red on clean HEAD&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Fix install, toolchain, or secrets with a human&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;owners&lt;/code&gt; is &lt;code&gt;unknown&lt;/code&gt; and last author is gone&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Ask in the team channel before editing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dirty files you did not create&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;git status&lt;/code&gt;, then stash or reset with review&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Test is green, path is owned, tree is clean&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Bound the path; keep the card in the PR&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agent wants to change lockfiles or CI&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Split that work; it is not a first PR&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;You cannot rerun the card command&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Do not request review&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Print the table in your notes if it helps. The point is a stop rule, not a vibe.&lt;/p&gt;

&lt;h2&gt;
  
  
  First PR after the card exists
&lt;/h2&gt;

&lt;p&gt;Keep the first PR inside the path you measured. One test file and one production file is enough. Do not let the agent “clean up” neighbors.&lt;/p&gt;

&lt;p&gt;Paste the session card at the top of the PR body. Then add the command a reviewer can rerun. Example markdown:&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="gu"&gt;## Session card&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; SHA: 9f3c1a2
&lt;span class="p"&gt;-&lt;/span&gt; Path: src/billing
&lt;span class="p"&gt;-&lt;/span&gt; Command: npm test -- --runTestsByPath src/billing/invoice.test.ts
&lt;span class="p"&gt;-&lt;/span&gt; Exit: 0
&lt;span class="p"&gt;-&lt;/span&gt; Owners: @billing-oncall
&lt;span class="p"&gt;-&lt;/span&gt; Last author: Alex &lt;span class="nv"&gt;&amp;lt;alex@example.com&amp;gt;&lt;/span&gt;

&lt;span class="gu"&gt;## Replay&lt;/span&gt;

npm ci
npm test -- --runTestsByPath src/billing/invoice.test.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ask the agent for a diff against that SHA only. Reject a patch that retargets &lt;code&gt;main&lt;/code&gt; while you slept. Reject a patch that rewrites the test command.&lt;/p&gt;

&lt;p&gt;If the model changes assertions to match new code, stop. Your job on day one is a green replay, not a greener story. Restore the original test and shrink the change.&lt;/p&gt;

&lt;h2&gt;
  
  
  When a free server is useful
&lt;/h2&gt;

&lt;p&gt;Laptops on day one are often thin. You may lack a local model runtime. You still need the session card before any remote chat.&lt;/p&gt;

&lt;p&gt;Disclosure: This article was prepared as part of MonkeyCode's product outreach. MonkeyCode is an open-source project with free model access and a free server option. Use it only after &lt;code&gt;session-card.json&lt;/code&gt; exists and the named test is green on your checkout.&lt;/p&gt;

&lt;p&gt;Keep the same path bound on the server. Paste the card fields into the session notes. Do not paste secrets, &lt;code&gt;.env&lt;/code&gt; files, or production dumps. If the server cannot rerun your exact test command, treat the output as untrusted text.&lt;/p&gt;

&lt;h2&gt;
  
  
  If you cannot explain the diff
&lt;/h2&gt;

&lt;p&gt;Revert beats a guessed explanation. Use the SHA from the card as the recovery point.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git fetch origin
git switch main
git revert &lt;span class="nt"&gt;--no-edit&lt;/span&gt; &amp;lt;pr-merge-sha&amp;gt;
&lt;span class="c"&gt;# or restore your branch to the frozen card SHA&lt;/span&gt;
git switch first-hour/session-card
git reset &lt;span class="nt"&gt;--hard&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;python3 &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s1"&gt;'import json;print(json.load(open("session-card.json"))["head_sha"])'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do not open a second agent to “fix the revert.” Rerun the named test first. If it fails on the frozen SHA, your card was already a lie.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limitations
&lt;/h2&gt;

&lt;p&gt;This workflow does not replace CI. A green local test can still miss OS, timezone, or service wiring. &lt;code&gt;CODEOWNERS&lt;/code&gt; grep is naive and misses glob owners. Monorepos may need a package filter the script does not infer.&lt;/p&gt;

&lt;p&gt;The script also trusts the command you pass. A wrong command that exits zero is a false gate. You must copy the command from CI or a teammate, not from a model.&lt;/p&gt;

&lt;p&gt;It will not help if tests need private services you cannot run. In that case, record &lt;code&gt;unknown&lt;/code&gt; for the test and pair with the owner. Do not fake a unit test the suite never had.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who should skip this
&lt;/h2&gt;

&lt;p&gt;Skip this if you already run the full suite locally every morning. Skip it during an active incident when a lead already named the command. Skip it if policy forbids extra servers or extra JSON in PRs.&lt;/p&gt;

&lt;p&gt;Staff engineers pairing on a known path can shorten the card. Juniors on a first checkout should not. The card is for people who still need a map.&lt;/p&gt;

&lt;p&gt;Do not start your first hour with an agent. Name one green test, freeze the card, then keep the first PR small enough to replay.&lt;/p&gt;

</description>
      <category>git</category>
      <category>beginners</category>
      <category>ai</category>
      <category>testing</category>
    </item>
    <item>
      <title>Build a Path Deny List Before Your First Agent PR</title>
      <dc:creator>Quinn Zhu</dc:creator>
      <pubDate>Sun, 20 Sep 2026 11:44:58 +0000</pubDate>
      <link>https://dev.to/gitgo_5662/build-a-path-deny-list-before-your-first-agent-pr-3lje</link>
      <guid>https://dev.to/gitgo_5662/build-a-path-deny-list-before-your-first-agent-pr-3lje</guid>
      <description>&lt;p&gt;Your first agent patch will wander into the wrong files. Freeze those paths before you write a prompt. A junior needs a deny list on day one.&lt;/p&gt;

&lt;p&gt;Agents will chase a green local run. They do not share your merge risk. Secrets, lockfiles, and CI configs look like easy edits. They are the edits that wake the whole team.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this gate exists
&lt;/h2&gt;

&lt;p&gt;You joined a new repo this morning. You can clone it and run tests. You cannot yet judge blast radius well.&lt;/p&gt;

&lt;p&gt;An agent will refresh a lockfile without asking. It will rewrite a workflow file next. It will open env examples and guess values. None of that belongs in your first PR.&lt;/p&gt;

&lt;p&gt;You need a written freeze you can grep. Your memory fails fast under time pressure. A written file does not fail that way.&lt;/p&gt;

&lt;h2&gt;
  
  
  The deny list in plain terms
&lt;/h2&gt;

&lt;p&gt;Treat every path as allowed or frozen. Frozen paths never enter the agent context window. Those frozen paths must never enter &lt;code&gt;git add&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Use this decision table on day one. Copy it, then rename patterns for your repo.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path pattern&lt;/th&gt;
&lt;th&gt;Freeze?&lt;/th&gt;
&lt;th&gt;Why you freeze it&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;.env&lt;/code&gt;, &lt;code&gt;.env.*&lt;/code&gt;, &lt;code&gt;**/*.pem&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Secrets leak through prompts and diffs.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;**/credentials*&lt;/code&gt;, &lt;code&gt;**/*secret*&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;The names already signal production risk.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;package-lock.json&lt;/code&gt;, &lt;code&gt;yarn.lock&lt;/code&gt;, &lt;code&gt;pnpm-lock.yaml&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Lock churn hides the real change.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;Cargo.lock&lt;/code&gt;, &lt;code&gt;go.sum&lt;/code&gt;, &lt;code&gt;poetry.lock&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Same problem in other ecosystems.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;.github/workflows/**&lt;/code&gt;, &lt;code&gt;.gitlab-ci.yml&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;CI edits skip your reviewer set.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;CODEOWNERS&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Ownership files change who must sign.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;**/migrations/**&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Data rewrites are not first-PR work.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;infra/**&lt;/code&gt;, &lt;code&gt;terraform/**&lt;/code&gt;, &lt;code&gt;k8s/**&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Cloud diffs need a different owner.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;README.md&lt;/code&gt;, &lt;code&gt;CONTRIBUTING.md&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Docs are safe if you read them.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Source under the ticket path&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;That is the work you were assigned.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The table is a proposal, not team policy. Your reviewers may freeze even more paths. Ask them before you treat this as law.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Inventory the tree before you prompt
&lt;/h2&gt;

&lt;p&gt;Do this work in a clean clone. Do not open a chat window yet.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone git@example.com:your-org/your-repo.git
&lt;span class="nb"&gt;cd &lt;/span&gt;your-repo
git status
git log &lt;span class="nt"&gt;--oneline&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; 15
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should list the dangerous file names yourself. Do not ask a model to guess them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;find &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-type&lt;/span&gt; f &lt;span class="se"&gt;\(&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s1"&gt;'.env'&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s1"&gt;'.env.*'&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s1"&gt;'*.pem'&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s1"&gt;'CODEOWNERS'&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s1"&gt;'*lock.json'&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s1"&gt;'*lock.yaml'&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s1"&gt;'Cargo.lock'&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s1"&gt;'go.sum'&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s1"&gt;'.gitlab-ci.yml'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="se"&gt;\)&lt;/span&gt; &lt;span class="nt"&gt;-not&lt;/span&gt; &lt;span class="nt"&gt;-path&lt;/span&gt; &lt;span class="s1"&gt;'./.git/*'&lt;/span&gt; | &lt;span class="nb"&gt;sort&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save that output as your first artifact. You produced that list without an agent. If &lt;code&gt;find&lt;/code&gt; is noisy, narrow the names.&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;ls&lt;/span&gt; &lt;span class="nt"&gt;-la&lt;/span&gt;
&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-la&lt;/span&gt; .github/workflows 2&amp;gt;/dev/null &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true
ls&lt;/span&gt; &lt;span class="nt"&gt;-la&lt;/span&gt; infra terraform k8s 2&amp;gt;/dev/null &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Read &lt;code&gt;CODEOWNERS&lt;/code&gt; now if it exists. Note who owns workflows and infra paths. You will not stage those trees today.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Write a deny file you can grep
&lt;/h2&gt;

&lt;p&gt;Create &lt;code&gt;.agent-untouchable&lt;/code&gt; at your repo root. Keep the deny file boring and short. You should use only one pattern per line.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# proposal: junior path freeze, not a security boundary
.env
.env.*
*.pem
**/credentials*
**/*secret*
package-lock.json
yarn.lock
pnpm-lock.yaml
Cargo.lock
go.sum
poetry.lock
.github/workflows/**
.gitlab-ci.yml
CODEOWNERS
**/migrations/**
infra/**
terraform/**
k8s/**
.agent-untouchable
check-untouchable.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep the file local until the team wants it. Copy it outside the worktree as well.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cp&lt;/span&gt; .agent-untouchable &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/.agent-untouchable.&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;basename&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$PWD&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A bad reset then cannot eat your freeze list. You still own the source of truth.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Install a checker that fails loud
&lt;/h2&gt;

&lt;p&gt;This checker script is a proposal only. Run it only on your local machine. Do not treat it as production policy.&lt;/p&gt;

&lt;p&gt;It compares staged names to the deny list. It exits one when a frozen path is staged.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class="c"&gt;# check-untouchable.sh&lt;/span&gt;
&lt;span class="c"&gt;# proposal: local gate for a junior's first agent PR&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail
&lt;span class="nb"&gt;shopt&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; globstar nullglob

&lt;span class="nv"&gt;DENY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="p"&gt;.agent-untouchable&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$DENY&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"missing deny file: &lt;/span&gt;&lt;span class="nv"&gt;$DENY&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&amp;amp;2
  &lt;span class="nb"&gt;exit &lt;/span&gt;2
&lt;span class="k"&gt;fi

&lt;/span&gt;&lt;span class="nb"&gt;mapfile&lt;/span&gt; &lt;span class="nt"&gt;-t&lt;/span&gt; staged &amp;lt; &amp;lt;&lt;span class="o"&gt;(&lt;/span&gt;git diff &lt;span class="nt"&gt;--cached&lt;/span&gt; &lt;span class="nt"&gt;--name-only&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="k"&gt;${#&lt;/span&gt;&lt;span class="nv"&gt;staged&lt;/span&gt;&lt;span class="p"&gt;[@]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;-eq&lt;/span&gt; 0 &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"nothing staged"&lt;/span&gt;
  &lt;span class="nb"&gt;exit &lt;/span&gt;0
&lt;span class="k"&gt;fi

&lt;/span&gt;&lt;span class="nv"&gt;fail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0
&lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nv"&gt;IFS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;read&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; pat&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-z&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$pat&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$pat&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;~ ^# &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;continue
  for &lt;/span&gt;f &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;staged&lt;/span&gt;&lt;span class="p"&gt;[@]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
    if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$f&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nv"&gt;$pat&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
      &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"FROZEN path staged: &lt;/span&gt;&lt;span class="nv"&gt;$f&lt;/span&gt;&lt;span class="s2"&gt; (pattern &lt;/span&gt;&lt;span class="nv"&gt;$pat&lt;/span&gt;&lt;span class="s2"&gt;)"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&amp;amp;2
      &lt;span class="nv"&gt;fail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1
    &lt;span class="k"&gt;fi
  done
done&lt;/span&gt; &amp;lt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$DENY&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$fail&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-ne&lt;/span&gt; 0 &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"unstage frozen paths before you request review"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&amp;amp;2
  &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi

&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"staged paths are outside the deny list"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make it executable before you rely on it.&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;chmod&lt;/span&gt; +x check-untouchable.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wire a local hook if you want friction. Skip shared repo hooks on day one. You do not own hook policy yet.&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; &lt;span class="nt"&gt;-p&lt;/span&gt; .git/hooks
&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; .git/hooks/pre-commit &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;'
#!/usr/bin/env bash
exec "&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;git rev-parse &lt;span class="nt"&gt;--show-toplevel&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="sh"&gt;/check-untouchable.sh"
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;span class="nb"&gt;chmod&lt;/span&gt; +x .git/hooks/pre-commit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A local hook protects your index only. It does not police the remote branch. That is enough for a first PR.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Prove the checker with a fake diff
&lt;/h2&gt;

&lt;p&gt;Never trust a gate you have not failed. Stage one frozen file on purpose.&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;echo&lt;/span&gt; &lt;span class="s2"&gt;"# probe"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; README.md
&lt;span class="c"&gt;# pick a real frozen file if it exists&lt;/span&gt;
git add package-lock.json 2&amp;gt;/dev/null &lt;span class="o"&gt;||&lt;/span&gt; git add .github/workflows 2&amp;gt;/dev/null &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
./check-untouchable.sh &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true
&lt;/span&gt;git reset HEAD
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You want a red line from the checker. A silent pass teaches you nothing useful. Record the exact command you just ran.&lt;/p&gt;

&lt;p&gt;If the pattern language misses, tighten the lines. Bash globbing is not the gitignore language. Enable &lt;code&gt;globstar&lt;/code&gt; if you need recursive stars.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# already in the script; re-run after edits&lt;/span&gt;
&lt;span class="nb"&gt;shopt&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; globstar nullglob
./check-untouchable.sh &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Retest the fake diff after that change. Keep the failing output in your notes. You now have proof the gate can fire.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Bound the prompt after the freeze
&lt;/h2&gt;

&lt;p&gt;Only now may you talk to an agent. Paste the ticket path and the deny file. Do not paste env files or keys.&lt;/p&gt;

&lt;p&gt;Use a prompt that states the bound twice. This block is a template, not a transcript.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Edit only files under app/billing/.
Do not read or write paths in .agent-untouchable.
Do not refresh lockfiles.
Do not edit workflows.
Return a file list before any patch.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You must demand the full file list first. Then you may accept a bounded patch. Then run the checker, then known tests.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# replace with the test command from README&lt;/span&gt;
python &lt;span class="nt"&gt;-m&lt;/span&gt; pytest &lt;span class="nt"&gt;-q&lt;/span&gt;
&lt;span class="c"&gt;# or&lt;/span&gt;
npm &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;--silent&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If tests are unknown, stop the patch. You do not edit a repo you cannot run. Keep this workflow on path control only.&lt;/p&gt;

&lt;h2&gt;
  
  
  A worked example for a billing ticket
&lt;/h2&gt;

&lt;p&gt;You were assigned ticket &lt;code&gt;BILL-214&lt;/code&gt; this morning. The ticket names &lt;code&gt;app/billing/invoice.py&lt;/code&gt; only. That is the only product path you will stage.&lt;/p&gt;

&lt;p&gt;Your agent now returns four changed files. You read the names before any patch.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app/billing/invoice.py
app/billing/invoice_test.py
package-lock.json
.github/workflows/ci.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two of those four names are frozen. You reject the whole patch at once. You do not "fix" the workflow as a favor.&lt;/p&gt;

&lt;p&gt;Restate the bound in one short prompt.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Return a patch for app/billing/invoice.py
and app/billing/invoice_test.py only.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Stage only those two files after that. Run the checker on the index. Run the tests you already know well.&lt;/p&gt;

&lt;p&gt;This is slower than accepting the full diff. Slower is the point on day one. You are learning the repo, not farming merges.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you paste, and what you never paste
&lt;/h2&gt;

&lt;p&gt;You may paste the deny file itself. You may paste the ticket path next. You may paste a failing test name.&lt;/p&gt;

&lt;p&gt;You never paste a &lt;code&gt;.env&lt;/code&gt; file. You never paste &lt;code&gt;id_rsa&lt;/code&gt; or pem files. You never paste production URLs with tokens.&lt;/p&gt;

&lt;p&gt;If a README shows a sample key, stop. Replace it with &lt;code&gt;REDACTED&lt;/code&gt; before any chat. The agent does not need real credentials to edit billing math.&lt;/p&gt;

&lt;p&gt;This rule is stronger than the checker. The checker only sees git state. The chat sees whatever you paste in.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where a free coding agent fits
&lt;/h2&gt;

&lt;p&gt;You can draft the deny list by hand. You should draft that list yourself first. That inventory work is a junior skill.&lt;/p&gt;

&lt;p&gt;You may still want a model for extra patterns. Keep all secrets out of that chat. Disclosure: This article was prepared as part of MonkeyCode's product outreach.&lt;/p&gt;

&lt;p&gt;MonkeyCode is an open source coding-agent project. It offers free model access and a free server option. This article does not list model names or quotas. Those details change and must be checked on the project page.&lt;/p&gt;

&lt;p&gt;Want a free model for extra pattern suggestions? MonkeyCode's free model access covers that narrow step. Use a free server only as a scratch runner. Run &lt;code&gt;check-untouchable.sh&lt;/code&gt; there if your laptop is busy. Do not upload env files or production keys.&lt;/p&gt;

&lt;p&gt;The deny list exists to stop that habit. After the freeze file exists, the rest of the work is git.&lt;/p&gt;

&lt;h2&gt;
  
  
  Failure modes you should expect
&lt;/h2&gt;

&lt;p&gt;The checker will miss renamed files often. A move plus &lt;code&gt;git add -A&lt;/code&gt; can sneak past a stale pattern.&lt;/p&gt;

&lt;p&gt;The checker will also miss generated files. A build may write a lockfile you never meant to stage.&lt;/p&gt;

&lt;p&gt;The checker will not stop a paste into a chat box. Frozen paths in git are not frozen in your clipboard.&lt;/p&gt;

&lt;p&gt;If the agent rewrites the deny file, you lost. Protect the deny file itself from edits.&lt;/p&gt;

&lt;p&gt;Add those lines to the deny list. Then restage nothing from that frozen set.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limitations
&lt;/h2&gt;

&lt;p&gt;This local workflow is not authorization at all. It is not a secret scanning tool. It is not a &lt;code&gt;CODEOWNERS&lt;/code&gt; file replacement.&lt;/p&gt;

&lt;p&gt;Bash globbing is a weak matcher here. It will not parse gitignore files correctly. It will not understand submodules or sparse checkout.&lt;/p&gt;

&lt;p&gt;A determined agent can still edit a frozen file on disk. Your hook only sees &lt;code&gt;git add&lt;/code&gt; events. Those unstaged edits still remain on disk.&lt;/p&gt;

&lt;p&gt;The table above is only a proposal. It is not your company's written policy. Ask your reviewer which paths are actually sacred.&lt;/p&gt;

&lt;p&gt;Do not publish a deny file that names internal hosts. Keep every pattern generic and boring instead.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who should not use this
&lt;/h2&gt;

&lt;p&gt;Skip this workflow if you were hired to change CI. Skip it if the ticket is a lockfile bump. Skip it during an incident when the frozen path is the fix.&lt;/p&gt;

&lt;p&gt;Staff engineers with merge rights may need those files. This gate is for a junior's first agent PR. It is not a repo-wide standard until the team says so.&lt;/p&gt;

&lt;p&gt;Do not use a remote agent host for an uncleared private repo. A free server is not a legal review.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep the freeze, then request review
&lt;/h2&gt;

&lt;p&gt;Write the deny list before the first prompt. Fail the checker on purpose once today. Keep frozen paths out of the index.&lt;/p&gt;

&lt;p&gt;The agent can still write code you understand. It cannot wander into secrets, locks, and CI today.&lt;/p&gt;

&lt;p&gt;Ask your reviewer to confirm the freeze list. Then open the PR with the two files you can name.&lt;/p&gt;

</description>
      <category>git</category>
      <category>beginners</category>
      <category>ai</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
