<?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>Forem</title>
    <description>The most recent home feed on Forem.</description>
    <link>https://forem.com</link>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed"/>
    <language>en</language>
    <item>
      <title>Retro gaming guide: CSS scanlines, Orbitron and dark theme without JS</title>
      <dc:creator>Odilon HUGONNOT</dc:creator>
      <pubDate>Wed, 20 May 2026 09:00:06 +0000</pubDate>
      <link>https://forem.com/ohugonnot/retro-gaming-guide-css-scanlines-orbitron-and-dark-theme-without-js-424k</link>
      <guid>https://forem.com/ohugonnot/retro-gaming-guide-css-scanlines-orbitron-and-dark-theme-without-js-424k</guid>
      <description>&lt;p&gt;I needed a buying guide for portable retro consoles — the kind of page you browse from a couch on a Saturday night before caving in and ordering something on eBay. Static content, no dynamic behaviour, no API. A perfect excuse to write unbounded CSS without having to justify it to a team. The vision: a cyberpunk dark theme, scanlines that echo old CRT screens, retro-futuristic typography. And crucially, no framework, no JavaScript whatsoever.&lt;/p&gt;

&lt;p&gt;What I learned building it is that the most visually striking effects don't come from animation libraries — they come from the right combination of CSS gradients, pseudo-elements, and well-structured custom properties. Here's how it works.&lt;/p&gt;

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

&lt;p&gt;The target page: &lt;a href="https://www.web-developpeur.com/retro-consoles.html" rel="noopener noreferrer"&gt;retro-consoles.html&lt;/a&gt;. A buying guide covering around twenty portable retro consoles — Game Boy, Analogue Pocket, Miyoo Mini, Anbernic RG35XX and the rest. Each console gets its specs, its price, its pros and cons.&lt;/p&gt;

&lt;p&gt;The technical constraint was simple: a static page hosted on the same Apache server as the CV, zero runtime dependencies. The aesthetic goal was more ambitious: recreating the visual atmosphere of a 1980s CRT screen in a modern browser. The cyan accent colour &lt;code&gt;#00d4ff&lt;/code&gt;, chosen for its resemblance to phosphor green shifted to electric blue, sets the tone. The rest of the theme follows from that.&lt;/p&gt;

&lt;h2&gt;
  
  
  The scanlines effect — pure CSS
&lt;/h2&gt;

&lt;p&gt;Scanlines are the most visually recognisable effect and the simplest to implement. The idea: a &lt;code&gt;::before&lt;/code&gt; pseudo-element fixed to the viewport, covering the entire page, with a &lt;code&gt;repeating-linear-gradient&lt;/code&gt; that alternates transparent and semi-opaque every two pixels.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="nd"&gt;::before&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;fixed&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="py"&gt;inset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;pointer-events&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;z-index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;9999&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;repeating-linear-gradient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="nb"&gt;bottom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nb"&gt;transparent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nb"&gt;transparent&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.08&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.08&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="m"&gt;2px&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three decisions here that are worth spelling out.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;position: fixed&lt;/code&gt;, not &lt;code&gt;absolute&lt;/code&gt;.&lt;/strong&gt; The effect needs to overlay all content even when scrolling, like a real physical screen. &lt;code&gt;fixed&lt;/code&gt; stays anchored to the viewport.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;pointer-events: none&lt;/code&gt;.&lt;/strong&gt; Without this, the pseudo-element absorbs all clicks and the page becomes unusable. A classic oversight with CSS overlays.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Opacity at 0.08 on the dark lines.&lt;/strong&gt; That number is arbitrary but the result of several iterations. Too strong (0.2+) and the content becomes unreadable. Too weak (0.03) and the effect disappears on light backgrounds — but here the background is dark, so contrast works at low values.&lt;/p&gt;

&lt;h2&gt;
  
  
  Retro typography: Orbitron, Space Mono, why these choices
&lt;/h2&gt;

&lt;p&gt;Type choices in a themed design account for 70% of the visual identity. Three fonts, three distinct roles:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* Headings: Orbitron — geometric shapes, angular uppercase */&lt;/span&gt;
&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;h3&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;'Orbitron'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;monospace&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;letter-spacing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.05em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;text-transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;uppercase&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* Prices, technical specs: Space Mono — monospace with personality */&lt;/span&gt;
&lt;span class="nc"&gt;.price&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
&lt;span class="nc"&gt;.spec-value&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;'Space Mono'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;monospace&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* Body copy: DM Sans — readable, neutral, unobtrusive */&lt;/span&gt;
&lt;span class="nt"&gt;body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;'DM Sans'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;sans-serif&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Orbitron&lt;/strong&gt; for headings: the archetypal retro-futuristic typeface, drawn with geometric shapes and right angles. Works equally well for "GAME BOY" and "ANALOGUE POCKET". The trade-off: it's unreadable at body copy sizes. A heading set in Orbitron at 14px makes you want to close the tab.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Space Mono&lt;/strong&gt; for numerical data. A monospace designed by Colophon Foundry with more personality than Courier or Roboto Mono. Prices aligned vertically in Space Mono on a dark background recall 1980s terminal screens.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DM Sans&lt;/strong&gt; for everything else. The rule is simple: never put a display typeface in body copy. Orbitron for 500 words of console descriptions would be cruel.&lt;/p&gt;

&lt;h2&gt;
  
  
  Custom properties for the entire theme
&lt;/h2&gt;

&lt;p&gt;A coherent dark theme with a single accent colour is best managed through custom properties from the start. Not a single hardcoded colour anywhere in the CSS — everything goes through &lt;code&gt;:root&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nd"&gt;:root&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;/* Backgrounds */&lt;/span&gt;
    &lt;span class="py"&gt;--bg-primary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="m"&gt;#0a0a0f&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="py"&gt;--bg-secondary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#111118&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="py"&gt;--bg-card&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;      &lt;span class="m"&gt;#16161f&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="py"&gt;--bg-card-hover&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="m"&gt;#1c1c28&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c"&gt;/* Main accent */&lt;/span&gt;
    &lt;span class="py"&gt;--accent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;       &lt;span class="m"&gt;#00d4ff&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="py"&gt;--accent-dim&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;212&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.15&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="py"&gt;--accent-glow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;20px&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;212&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c"&gt;/* Text */&lt;/span&gt;
    &lt;span class="py"&gt;--text-primary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="m"&gt;#e8e8f0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="py"&gt;--text-secondary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="m"&gt;#9090a8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="py"&gt;--text-muted&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;    &lt;span class="m"&gt;#5a5a72&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c"&gt;/* Borders */&lt;/span&gt;
    &lt;span class="py"&gt;--border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;        &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;212&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="py"&gt;--border-strong&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;212&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few details that matter. &lt;code&gt;--accent-dim&lt;/code&gt;: a heavily attenuated version of the accent for hover backgrounds and badges. Without it, you end up recomputing &lt;code&gt;rgba(0, 212, 255, X)&lt;/code&gt; all over the stylesheet. &lt;code&gt;--accent-glow&lt;/code&gt;: the neon halo on featured elements, defined once as a &lt;code&gt;box-shadow&lt;/code&gt; value.&lt;/p&gt;

&lt;p&gt;The card hover glow then reduces to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.console-card&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--bg-card-hover&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nl"&gt;border-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--border-strong&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--accent-glow&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;translateY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;-2px&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nl"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;all&lt;/span&gt; &lt;span class="m"&gt;0.2s&lt;/span&gt; &lt;span class="n"&gt;ease&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Responsive layout without a framework
&lt;/h2&gt;

&lt;p&gt;CSS Grid with &lt;code&gt;auto-fill&lt;/code&gt; and &lt;code&gt;minmax&lt;/code&gt; — the only way to build a truly responsive multi-column layout without a single media query for the cards:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.consoles-grid&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="py"&gt;grid-template-columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;auto-fill&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;minmax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;280px&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="py"&gt;gap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;24px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With &lt;code&gt;minmax(280px, 1fr)&lt;/code&gt;, the browser calculates how many columns fit. On a 1440px screen: 4 columns. On an iPad at 768px: 2 columns. On a phone: 1 column. No manual breakpoints needed for the grid itself.&lt;/p&gt;

&lt;p&gt;Media queries are still needed for other adjustments: reducing Orbitron &lt;code&gt;font-size&lt;/code&gt; on mobile (geometric headline fonts are wide), switching the header from two columns to one, adjusting padding.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.page-header&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="py"&gt;grid-template-columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;align-items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="py"&gt;gap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;32px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;768px&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;.page-header&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="py"&gt;grid-template-columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nt"&gt;h1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;clamp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1.4rem&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;5vw&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;2.5rem&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;clamp()&lt;/code&gt; for Orbitron headings: essential. Without it, a 2.5rem &lt;code&gt;h1&lt;/code&gt; in Orbitron overflows the viewport on an iPhone SE.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This project reinforced something I knew in theory but regularly underestimate in practice: a strong visual design doesn't require JavaScript. The card hover animation, the scanlines effect, the neon glow — all of it works with &lt;code&gt;transition&lt;/code&gt;, &lt;code&gt;box-shadow&lt;/code&gt;, and a pseudo-element. The browser handles the rendering on the GPU, without a single &lt;code&gt;requestAnimationFrame&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The real complexity wasn't technical — it was visual calibration. Finding the scanline opacity that creates atmosphere without hurting legibility. Choosing a cyan luminosity that evokes phosphor without burning eyes. These are decisions that don't get written in code; they get validated by eye.&lt;/p&gt;

&lt;p&gt;The result: &lt;a href="https://www.web-developpeur.com/retro-consoles.html" rel="noopener noreferrer"&gt;retro-consoles.html&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>css</category>
      <category>darktheme</category>
      <category>design</category>
      <category>sideprojects</category>
    </item>
    <item>
      <title>How to Build an Autonomous AI Coding Agent That Opens GitHub PRs Overnight</title>
      <dc:creator>pickuma</dc:creator>
      <pubDate>Wed, 20 May 2026 08:59:27 +0000</pubDate>
      <link>https://forem.com/pickuma/how-to-build-an-autonomous-ai-coding-agent-that-opens-github-prs-overnight-1o0b</link>
      <guid>https://forem.com/pickuma/how-to-build-an-autonomous-ai-coding-agent-that-opens-github-prs-overnight-1o0b</guid>
      <description>&lt;p&gt;You file an issue before bed: "Migrate the date helpers off moment.js." You wake up to a draft pull request — branch created, files changed, tests green, waiting for review. That is the pitch for an autonomous AI coding agent, and the surprising part is how little of it is novel. The hard problem is not the model. It is the loop around the model: the harness that turns a task into a reviewable PR with nobody in the chair.&lt;/p&gt;

&lt;p&gt;We built this pattern and ran it against real repositories. What follows is the architecture that held up, the GitHub wiring that kept it safe, and an honest account of which tasks it finishes and which it quietly botches.&lt;/p&gt;

&lt;h2&gt;
  
  
  Anatomy of the overnight loop
&lt;/h2&gt;

&lt;p&gt;An autonomous coding agent is a state machine with a language model wired into a few of its transitions. Strip away the marketing and five stages remain:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Ingest&lt;/strong&gt; — pull the task (a GitHub issue, a queue row, a line in a file) and the repo into a clean working directory.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Plan&lt;/strong&gt; — one model call reads the task and the repo layout, then emits a concrete plan: which files change, in what order, and what "done" looks like.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Execute&lt;/strong&gt; — a separate model call edits files to match the plan, one coherent change at a time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verify&lt;/strong&gt; — run the test suite, the type checker, and the linter.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Package&lt;/strong&gt; — commit, push a branch, open a pull request.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The mistake most first attempts make is collapsing stages two through four into one enormous prompt: "here is the repo, here is the task, output the diff." That works for a three-line fix and falls apart on anything larger. Chaining narrow steps buys you something a single prompt cannot — a checkpoint between each stage where the work can be inspected before the agent commits to it.&lt;/p&gt;

&lt;p&gt;Stage four is what separates a coding agent from a code generator. A model with no feedback loop will cheerfully report success on code that does not compile. Wire the executor to the verifier so a failing test run feeds the actual error text back into the next edit. Bound the retries — three attempts is a sane ceiling — and if the agent still cannot reach green, it should stop, open the PR as a draft, and log the failure rather than push broken code or loop forever burning tokens.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;An autonomous agent with repo write access is a contributor you have never met. Give it a fine-grained personal access token scoped to a single repository — never the org-wide token sitting in your shell. Run the execute stage in a container or disposable VM, not on your laptop, because generated code runs &lt;code&gt;npm install&lt;/code&gt; and whatever else it decides it needs. Keep branch protection on &lt;code&gt;main&lt;/code&gt; so the worst plausible outcome is a bad pull request, not a bad commit on your default branch.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Wiring it to GitHub without losing a finger
&lt;/h2&gt;

&lt;p&gt;Once the agent has a green working tree, the GitHub mechanics are routine. The pattern that held up for us:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;One branch per task&lt;/strong&gt;, named predictably — &lt;code&gt;agent/142-moment-migration&lt;/code&gt;, keyed off the issue number. Predictable names make reruns idempotent: if the branch already exists, update it instead of spawning a duplicate.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open the PR as a draft&lt;/strong&gt; and assign yourself as reviewer. Draft status tells the rest of the team the change is not merge-ready and discourages a reflexive approval.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Label every bot-authored PR&lt;/strong&gt; — &lt;code&gt;agent-generated&lt;/code&gt; or similar. That label is your provenance trail, and if the diff reaches users it is the basis for any disclosure you owe them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Let CI run&lt;/strong&gt; on the agent's PR exactly as it would on a human's. CI is the safety net the agent's own verify stage cannot fully replace, because it runs in a clean environment you control rather than the agent's sandbox.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;gh&lt;/code&gt; CLI keeps packaging short: &lt;code&gt;gh pr create --draft --base main --head agent/142&lt;/code&gt;. For richer control — adding labels, requesting reviewers, reading PR state back — the Octokit REST client earns its dependency.&lt;/p&gt;

&lt;p&gt;For the trigger you have two clean options. A cron job firing at 2 a.m. drains a task queue overnight. Or a GitHub webhook: label an issue &lt;code&gt;agent-ready&lt;/code&gt;, and the labeling event starts a run. The webhook route is closer to a real workflow, because the task and its trigger live where your team already works.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it automates well — and where it stalls
&lt;/h2&gt;

&lt;p&gt;The overnight agent earns its keep on work that is mechanical but tedious: bumping a dependency and fixing the fallout, adding test coverage to an untested module, migrating a deprecated API call across a codebase, running a codemod, converting config files, tidying stale documentation. These tasks share one trait — "done" is objectively checkable. A passing test suite or a clean type check is enough for the verify stage to know it succeeded.&lt;/p&gt;

&lt;p&gt;It stalls on the opposite kind of work. Ambiguous requests ("make the dashboard feel faster"), cross-cutting architecture changes, anything resting on product judgment, and — most important — any task in a repo whose test suite is thin. No verify gate means no safety, and the agent's confidence in its own output is not a substitute for one.&lt;/p&gt;

&lt;p&gt;Two numbers decide whether this is worth running. The first is cost per run: every stage is one or more model calls, and a non-trivial task with retries can reach dozens. Set a hard token or dollar ceiling per run so a stuck agent cannot run up a bill while you sleep. The second is PR acceptance rate — the share of generated PRs you merge without substantial rewriting. If you rewrite more than you keep, the tasks are scoped too loosely; tighten them until the agent succeeds reliably, then widen the scope carefully from there.&lt;/p&gt;

&lt;p&gt;The morning review stays non-negotiable. The agent's job is to hand you a pull request you can judge in a few minutes instead of work that would have cost you an hour. A bad PR you rubber-stamp at 9 a.m. is worse than no PR — so treat every overnight diff as untrusted until CI is green and you have read it yourself. Built this way, the agent is not a replacement for you. It is a night shift that handles only the boring parts.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://pickuma.com/posts/build-autonomous-ai-coding-agent-github-prs-overnight/?utm_source=devto&amp;amp;utm_medium=crosspost&amp;amp;utm_campaign=blog" rel="noopener noreferrer"&gt;pickuma.com&lt;/a&gt;. Subscribe to &lt;a href="https://pickuma.com/rss.xml" rel="noopener noreferrer"&gt;the RSS&lt;/a&gt; or follow &lt;a href="https://bsky.app/profile/pickuma.bsky.social" rel="noopener noreferrer"&gt;@pickuma.bsky.social&lt;/a&gt; for new reviews.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>tutorial</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Continual Harness: The Gemini Pokémon Agent That Rewrites Its Own Loop</title>
      <dc:creator>pickuma</dc:creator>
      <pubDate>Wed, 20 May 2026 08:58:10 +0000</pubDate>
      <link>https://forem.com/pickuma/continual-harness-the-gemini-pokemon-agent-that-rewrites-its-own-loop-2blk</link>
      <guid>https://forem.com/pickuma/continual-harness-the-gemini-pokemon-agent-that-rewrites-its-own-loop-2blk</guid>
      <description>&lt;p&gt;Most of the work that makes an AI agent good never happens inside the model. It happens in the harness — the code that feeds the model its observations, defines its tools, trims its context, and decides what to do with each response. When an agent fails, the usual fix is a human editing that harness: rewording a tool description, adding a memory store, changing how a screenshot gets summarized. The Continual Harness work, from the teams behind Gemini Plays Pokémon and the PokeAgent benchmark, pushes on a sharper question — what if the model edited the harness itself, while the run was still going?&lt;/p&gt;

&lt;h2&gt;
  
  
  The harness is where agents actually live
&lt;/h2&gt;

&lt;p&gt;Gemini Plays Pokémon was a public demonstration: a Gemini model worked through a Game Boy Pokémon title via a harness that turned the game into something a language model could reason about. The harness converted pixels into labeled screenshots, a map of the current area, and an inventory list, then exposed button presses and pathfinding helpers as tools. The model never touched raw emulator memory. It saw whatever the harness chose to show it, and it acted only through the tools the harness defined.&lt;/p&gt;

&lt;p&gt;That structure is not specific to Pokémon. A coding agent doesn't see your repository — it sees the files a retrieval step pulled in. A browser agent doesn't see a webpage — it sees an accessibility tree some extraction code produced. The harness is the agent's entire sensory system, its motor system, and its memory. The model is one component inside it.&lt;/p&gt;

&lt;p&gt;Which means most of the leverage in agent quality sits in the harness, not the weights. Teams running long agent tasks spend their time there: tightening tool descriptions, adding retry logic, changing how context gets summarized so the model stops losing the thread on long runs. That iteration is real engineering, and almost all of it happens offline — a human watches a failure, edits the scaffolding, and starts a fresh run.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When people say an agent "got smarter," they often mean the harness got better — the model checkpoint never moved. That is worth internalizing before you reach for a fine-tuning budget.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What "continual" changes
&lt;/h2&gt;

&lt;p&gt;The Continual Harness pattern moves that improvement loop inside the run. The agent is given write access to parts of its own harness. When it hits a recurring failure — say it keeps walking into a ledge because the pathfinding helper doesn't model one-way tiles — it can propose a change to that helper, apply it, and continue with the improved tool in hand. The scaffolding at hour ten is not the scaffolding the run started with.&lt;/p&gt;

&lt;p&gt;This is online adaptation, and it sits between two things developers already know. It is not fine-tuning: the model weights stay frozen. It is not ordinary in-context learning either, where the model only writes itself a note. The improvement lands as durable code — a function the agent rewrote — so it persists, it is inspectable, and it can be reverted. The model is playing the game and maintaining the controller at the same time.&lt;/p&gt;

&lt;p&gt;The reason this matters beyond a Pokémon stream: the manual harness-tuning loop is a bottleneck. Every agent team has a backlog of "the tool description is slightly wrong" and "the memory step drops the wrong thing" fixes that a human has to notice, diagnose, and ship. An agent that can do a slice of that work itself, on the failures it is actually hitting, compresses that loop from days to minutes.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;An agent with write access to its own harness can also break it. A bad edit to the navigation tool can strand the run; a bad edit to the context-trimming step can quietly degrade every later decision. This pattern is only safe with versioned edits, a fixed core loop the agent cannot touch, and automatic rollback when a change makes the feedback signal worse.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Borrowing the pattern for your own agents
&lt;/h2&gt;

&lt;p&gt;You do not need a Game Boy emulator to use this. The pattern reduces to four decisions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Separate the editable surface.&lt;/strong&gt; Decide explicitly which parts of the harness the agent may rewrite — tool wrappers, prompt templates, retrieval filters — and which are permanently off-limits: the loop that calls the model, the kill switch, anything that touches credentials or external writes. The self-improving part should be a small, well-fenced area.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Treat every harness edit as a commit.&lt;/strong&gt; A self-improvement is a diff. Give it a message, a test, and a revert path. If you cannot answer "what did the agent change, and how do I undo it," you do not have a continual harness — you have an agent slowly corrupting itself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Give it a feedback signal it can act on.&lt;/strong&gt; Pokémon has an obvious one: progress through the game. Your agent needs an equivalent — task success rate, an eval suite, a latency budget. Without a metric, the agent edits blind, and you cannot tell improvement from regression.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Start narrow.&lt;/strong&gt; Let the agent tune tool descriptions and retry thresholds long before you let it rewrite tool implementations. Widen the editable surface only as the rollback machinery proves itself.&lt;/p&gt;

&lt;p&gt;If you want to watch a constrained version of this loop before wiring it into an autonomous run, an AI-native code editor is the closest everyday analog: an agent proposes edits to real code, and you approve or reject each diff.&lt;/p&gt;

&lt;p&gt;The Continual Harness result is not that an agent finished a Pokémon game. It is that the harness — long treated as fixed scaffolding a human owns — can be a live, model-editable surface. For anyone building agents that run for hours, that reframes where the next improvement comes from.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://pickuma.com/posts/continual-harness-gemini-self-improving-agent-loop/?utm_source=devto&amp;amp;utm_medium=crosspost&amp;amp;utm_campaign=blog" rel="noopener noreferrer"&gt;pickuma.com&lt;/a&gt;. Subscribe to &lt;a href="https://pickuma.com/rss.xml" rel="noopener noreferrer"&gt;the RSS&lt;/a&gt; or follow &lt;a href="https://bsky.app/profile/pickuma.bsky.social" rel="noopener noreferrer"&gt;@pickuma.bsky.social&lt;/a&gt; for new reviews.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>tutorial</category>
      <category>productivity</category>
    </item>
    <item>
      <title>oh-my-agent v2: Nine New Skills, First-Class Cursor, and an 80/100 Benchmark</title>
      <dc:creator>pickuma</dc:creator>
      <pubDate>Wed, 20 May 2026 08:56:54 +0000</pubDate>
      <link>https://forem.com/pickuma/oh-my-agent-v2-nine-new-skills-first-class-cursor-and-an-80100-benchmark-16f6</link>
      <guid>https://forem.com/pickuma/oh-my-agent-v2-nine-new-skills-first-class-cursor-and-an-80100-benchmark-16f6</guid>
      <description>&lt;p&gt;If you have watched an AI coding agent install a package version that does not exist in your lockfile, or ship a function that fails your own lint config on the first commit, you already understand the gap oh-my-agent v2 is built to close. The framework's second major release adds nine new skills, promotes Cursor to a first-class vendor, and ships a benchmark that scores the toolkit 80 out of 100.&lt;/p&gt;

&lt;p&gt;Here is what v2 changes, and how to decide whether the additions target real failure modes or just expand the surface area.&lt;/p&gt;

&lt;h2&gt;
  
  
  What oh-my-agent does
&lt;/h2&gt;

&lt;p&gt;oh-my-agent is a skill layer that sits between you and whatever AI coding agent you run. The name borrows from oh-my-zsh, and the analogy holds: instead of configuring shell behavior, you configure agent behavior with reusable, composable instruction modules the project calls skills.&lt;/p&gt;

&lt;p&gt;The problem it targets is consistency. A raw coding agent keeps no durable memory of your project's conventions. Ask it to add a dependency and it may guess a version that is not in your lockfile. Ask it to write a component and it may ignore the lint config sitting in your repo root. These are not edge cases — they are the default behavior of an agent that treats every request as a fresh context.&lt;/p&gt;

&lt;p&gt;A skill in oh-my-agent is a packaged set of instructions and checks the agent loads when a task matches. One skill might force the agent to read your package.json and lockfile before proposing a version. Another might surface your linter rules before any code is written. The pitch is that you stop re-explaining the same constraints in every prompt.&lt;/p&gt;

&lt;h2&gt;
  
  
  The nine new skills in v2
&lt;/h2&gt;

&lt;p&gt;The v2 release adds nine skills. Three are worth calling out, because they map to problems most teams hit within a week of adopting an agent.&lt;/p&gt;

&lt;p&gt;deepsec handles security review. Instead of trusting the agent to remember secure patterns, the skill runs a structured pass over generated code, checking for the injection, secret-handling, and trust-boundary mistakes agents introduce when they optimize for making something work.&lt;/p&gt;

&lt;p&gt;observability pushes the agent to add logging, metrics, and tracing as it writes code, rather than leaving instrumentation as a follow-up task that never happens.&lt;/p&gt;

&lt;p&gt;docs drift detection is the one most teams underrate. When an agent changes a function signature or a config option, the matching documentation usually goes stale without anyone noticing. This skill flags the gap so docs and code stay in sync.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you adopt only one skill from v2, start with docs drift detection. Stale documentation is the failure you notice last and pay for longest: every new teammate and every future agent run inherits the wrong mental model from it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The remaining six skills round out areas like testing and project conventions. The pattern across all nine is the same: take a step a developer is supposed to do, and make it a non-optional part of the agent's workflow instead of a hope.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cursor becomes a first-class vendor
&lt;/h2&gt;

&lt;p&gt;Earlier oh-my-agent releases were built around one agent and treated the rest as second-class. v2 changes the model. A vendor is the underlying agent that executes skills, and Cursor is now a first-class vendor, which means skills are tested against it and ship with Cursor-specific wiring rather than a generic fallback.&lt;/p&gt;

&lt;p&gt;In practice, you can keep oh-my-agent's skill definitions in one place and run them through Cursor's agent without rewriting instructions per tool. For teams that have standardized on Cursor as their editor, that removes the main reason to maintain a separate, hand-rolled set of project rules.&lt;/p&gt;

&lt;p&gt;First-class status is a maintenance commitment, not a one-time feature. The thing to watch over the next few releases is whether Cursor support keeps pace with the primary vendor or quietly drifts behind it — the usual failure pattern for multi-vendor tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the 80/100 benchmark does and doesn't tell you
&lt;/h2&gt;

&lt;p&gt;v2 ships with a benchmark that scores the toolkit 80 out of 100. A published, repeatable number is useful on its own: it gives you a baseline to compare future releases against, and it signals the project is willing to measure itself instead of leaning on adjectives.&lt;/p&gt;

&lt;p&gt;Treat the number as a starting point, not a verdict. A benchmark reflects the tasks its authors chose. An 80 on the project's own suite tells you the skills behave as designed on that suite. It does not tell you how they perform on your codebase, your stack, or your conventions.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Do not adopt oh-my-agent on the strength of the 80/100 score alone. Run the skills against a real branch in your own repo and measure something you care about — failed lint checks, wrong dependency versions, broken builds — before and after. A framework's self-reported benchmark is a sales sheet until you reproduce it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The honest read on v2: the release aims squarely at the most common, least glamorous agent failures — wrong versions, ignored configs, stale docs — rather than chasing a flashier capability. That is the right target. The open question is operational. Nine new skills is a lot of surface to keep working across two first-class vendors, and the real proof will be whether release three holds the line.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://pickuma.com/posts/oh-my-agent-v2-nine-skills-cursor-vendor/?utm_source=devto&amp;amp;utm_medium=crosspost&amp;amp;utm_campaign=blog" rel="noopener noreferrer"&gt;pickuma.com&lt;/a&gt;. Subscribe to &lt;a href="https://pickuma.com/rss.xml" rel="noopener noreferrer"&gt;the RSS&lt;/a&gt; or follow &lt;a href="https://bsky.app/profile/pickuma.bsky.social" rel="noopener noreferrer"&gt;@pickuma.bsky.social&lt;/a&gt; for new reviews.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>tutorial</category>
      <category>productivity</category>
    </item>
    <item>
      <title>How Far Can a Small Coding Model Go With a Better Harness?</title>
      <dc:creator>Dmitry Barakhov</dc:creator>
      <pubDate>Wed, 20 May 2026 08:55:18 +0000</pubDate>
      <link>https://forem.com/dmitry_barakhov/how-far-can-a-small-coding-model-go-with-a-better-harness-18lb</link>
      <guid>https://forem.com/dmitry_barakhov/how-far-can-a-small-coding-model-go-with-a-better-harness-18lb</guid>
      <description>&lt;p&gt;Every time a coding agent underperforms, the default move is to swap in a bigger model. I wanted to see what happens if you refuse that move and fix everything else instead.&lt;/p&gt;

&lt;p&gt;The result: &lt;strong&gt;61.6% ± 1.9&lt;/strong&gt; on Terminal-Bench 2.0 with GPT-5.1-Codex-Mini — rank #41, in the same band as stock harnesses running flagship models a tier or two larger. 445 runs, $27, ~35 hours.&lt;/p&gt;

&lt;p&gt;This is not an argument that small models are secretly enough. It is an argument that the wrapper around the model is doing more work than most people give it credit for — and that you can see this clearly only when the model is small enough that harness mistakes actually hurt. What follows is a teardown of what survived.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reading the number
&lt;/h2&gt;

&lt;p&gt;The score is &lt;a href="https://www.tbench.ai/leaderboard/terminal-bench/2.0" rel="noopener noreferrer"&gt;verified on the official leaderboard&lt;/a&gt; at rank #41 as of May 14, 2026, across 89 tasks with 5 runs each. Leaderboards move, so I treat the rank as a timestamped snapshot rather than a permanent claim. The useful comparison is the neighborhood around that snapshot: entries immediately around rank #41 run on GPT-5.2, Claude Opus 4.6, and Gemini 3 Pro.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://raw.githubusercontent.com/sady4850/hookele-agent/main/docs/assets/leaderboard-2026-05-14.png" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyxnylv08rmgy0locf9jg.png" alt="Terminal-Bench 2.0 leaderboard around rank #41, May 14, 2026. Hookele is highlighted alongside entries running GPT-5.2, Claude Opus 4.6, and Gemini 3 Pro." width="800" height="381"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The wrapper, in other words, moves a smaller model into the same band as larger ones. The ±1.9 confidence interval comes from 5 runs per task across 89 tasks — wide enough that I treat the score as a band, not a precise rank, but tight enough that I do not think any one lucky trajectory is doing the work.&lt;/p&gt;

&lt;p&gt;One of the improvements that stood out during local iteration was something almost embarrassingly small: a 100-token classifier call at the start of each task that picks which Markdown skill files to drop into the system prompt. I do not have a clean 445-run ablation for every variant, so this is an engineering observation rather than a controlled benchmark result. Everything else (streaming retries, the V4A patcher, tool-output capping) is supporting structure that lets one loop keep moving without falling over.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://raw.githubusercontent.com/sady4850/hookele-agent/main/docs/assets/hookele-architecture.png?v=2" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmhviwogx3o7ajodpeg0e.png" alt="Hookele architecture" width="800" height="413"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A one-time skill router picks which Markdown playbooks get appended to the system prompt; after that, a single model runs a loop against seven tool entries. Side-effecting tools (&lt;code&gt;run_command&lt;/code&gt;, &lt;code&gt;apply_patch&lt;/code&gt;) mutate the Terminal-Bench container; read-only tools (&lt;code&gt;search_docs&lt;/code&gt;, &lt;code&gt;get_docs&lt;/code&gt;, &lt;code&gt;web_search&lt;/code&gt;) do not. A context policy caps tool outputs and preserves failures verbatim before they re-enter the model.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Terminal-Bench actually is
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/laude-institute/terminal-bench" rel="noopener noreferrer"&gt;Terminal-Bench 2.0&lt;/a&gt; drops your agent into a hardened container with a task instruction and a terminal. That is the whole interface — no iteration cap, no filesystem visibility from outside, no retries. If you want any of that, you build it yourself. Eighty-nine tasks span chess-engine guidance, R-to-Python Stan migrations, QEMU bring-up, hash cracking, Core Wars, CSV surgery via Vim macros, and a long tail of things that look obscure until they bite you.&lt;/p&gt;

&lt;p&gt;I picked it because frontier labs cite it themselves: it shows up in &lt;a href="https://openai.com/index/introducing-gpt-5-5/" rel="noopener noreferrer"&gt;OpenAI's GPT-5.5 announcement&lt;/a&gt; and in &lt;a href="https://www.anthropic.com/news/claude-opus-4-7" rel="noopener noreferrer"&gt;Anthropic's Claude Opus 4.7 post&lt;/a&gt; as a headline coding-agent score. A benchmark that labs use to grade their own flagships is a reasonable place to test whether a small model can punch up. Runs go through &lt;a href="https://github.com/harbor-framework/harbor" rel="noopener noreferrer"&gt;Harbor&lt;/a&gt;, the evaluation framework Terminal-Bench 2.0 standardized on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why a small model in the first place
&lt;/h2&gt;

&lt;p&gt;If the model is already the largest one available, every improvement is hard to attribute: did the harness help, or did the model muscle through? With a smaller model, harness mistakes show up quickly. Bad tool design, noisy context, fragile editing, and over-planning all become visible because the model has less slack.&lt;/p&gt;

&lt;p&gt;Hookele started from OpenAI's &lt;a href="https://github.com/openai/openai-cookbook/blob/main/examples/Build_a_coding_agent_with_GPT-5.1.ipynb" rel="noopener noreferrer"&gt;GPT-5.1 coding agent notebook&lt;/a&gt;, which wires &lt;code&gt;run_command&lt;/code&gt;, &lt;code&gt;apply_patch&lt;/code&gt;, &lt;code&gt;web_search&lt;/code&gt;, and Context7 docs lookup (a third-party library-documentation service) into the Responses API. The cookbook walks through the happy path. What follows is what happens when the happy path breaks: streams that drop mid-reasoning, diffs that fail to apply because context drifted by two characters, models that stall for 40 iterations without doing anything productive.&lt;/p&gt;

&lt;h2&gt;
  
  
  The loop
&lt;/h2&gt;

&lt;p&gt;Hookele is one model in one loop. On the first turn the executor calls &lt;code&gt;update_plan&lt;/code&gt; with 3–5 short steps and nothing else; after that the plan lives in the context window and the model can rewrite it whenever the approach changes. Every subsequent turn is a tool call against the same seven tool entries: &lt;code&gt;run_command&lt;/code&gt;, &lt;code&gt;apply_patch&lt;/code&gt;, &lt;code&gt;update_plan&lt;/code&gt;, &lt;code&gt;search_docs&lt;/code&gt;, &lt;code&gt;get_docs&lt;/code&gt;, &lt;code&gt;web_search&lt;/code&gt;, &lt;code&gt;task_complete&lt;/code&gt;. No router, no state machine, no separate planner. The cap is 60 iterations by default, but most successful runs finish in under 20.&lt;/p&gt;

&lt;p&gt;This is what survived deletion. An earlier version had a &lt;code&gt;gpt-5-mini&lt;/code&gt; planner that emitted JSON with &lt;code&gt;approach&lt;/code&gt; and &lt;code&gt;tools_needed&lt;/code&gt; to constrain the executor. It misclassified about one in five tasks — usually deciding "no file editing needed" on tasks whose solution was a small file edit — and the executor would dutifully not edit files. I removed it. The same pass took out a five-state scan→plan→act→verify→stop machine, an acceptance-criteria extractor, automated criteria evaluators, and dual-model routing. None of them survived contact with the benchmark. Each one had looked principled in isolation and added nothing the executor could not infer for itself.&lt;/p&gt;

&lt;p&gt;The tool surface got similar treatment. &lt;code&gt;list_files&lt;/code&gt; and &lt;code&gt;read_file&lt;/code&gt; came out because &lt;code&gt;run_command&lt;/code&gt; already does both through &lt;code&gt;ls&lt;/code&gt; and &lt;code&gt;cat&lt;/code&gt;, and exposing duplicate tools just gave the model another decision to make on every turn. Tool outputs are capped at 20K characters, head + tail, so a chatty &lt;code&gt;npm install&lt;/code&gt; cannot drown the context. Fewer tools means fewer decisions about which tool to use, which means more turns spent on the actual problem — and on a small model, every saved turn is real.&lt;/p&gt;

&lt;p&gt;The two pieces of low-level plumbing under the loop that actually earn their keep are the V4A patcher and the streaming layer.&lt;/p&gt;

&lt;h2&gt;
  
  
  The patcher
&lt;/h2&gt;

&lt;p&gt;Every edit goes through one tool: &lt;code&gt;apply_patch&lt;/code&gt;. I standardized on it instead of a generic &lt;code&gt;edit&lt;/code&gt; or &lt;code&gt;write&lt;/code&gt; because Codex models are &lt;a href="https://github.com/openai/codex/blob/main/codex-rs/apply-patch/apply_patch_tool_instructions.md" rel="noopener noreferrer"&gt;trained directly on the V4A patch format&lt;/a&gt;, and because structured diffs are easier to validate, retry, and explain than arbitrary file writes. V4A is OpenAI's diff envelope for Codex-family models — in Hookele, one payload can create, update, and delete files in a single call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;*** Begin Patch
*** Add File: hello.txt
+Hello world
*** Update File: src/app.py
@@ def greet():
-print("Hi")
+print("Hello, world!")
*** Delete File: obsolete.txt
*** End Patch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;@@&lt;/code&gt; line is the context anchor — the patcher locates the hunk by matching the line that follows. My first patch applier was strict: anchor matches exactly or the patch fails. It failed constantly. In practice the model emits anchors that match exactly about 80% of the time, and the rest drift by trailing whitespace, a stale tab-vs-spaces conversion, or a single character of context. Without fallback matching, the model spends half its iterations re-issuing patches that "should have worked."&lt;/p&gt;

&lt;p&gt;I ported the Agents SDK V4A engine (353 lines) and added three-level fuzzy context matching: try exact, then with trailing whitespace stripped, then with leading and trailing whitespace stripped. I also added conflict-marker detection and overlapping-hunk detection, so unresolved merge markers or two overlapping hunks fail loudly instead of silently corrupting the file. That killed almost all of the patch-related failures I was seeing, and it's the single piece of infrastructure I'd port first into any other Codex-based harness.&lt;/p&gt;

&lt;h2&gt;
  
  
  Streaming
&lt;/h2&gt;

&lt;p&gt;Streaming in Hookele is not a latency feature. It exists because long model turns drop mid-stream more often than you'd expect — TCP resets, TLS handshake failures, incomplete chunked reads, server-side &lt;code&gt;response.incomplete&lt;/code&gt;. Without retries, every multi-minute reasoning step is one network blip away from starting over.&lt;/p&gt;

&lt;p&gt;Hookele retries up to five times with exponential backoff, pattern-matching the exception against a list of transport-level signals (connection reset, broken pipe, TLS handshake, peer closed connection, and a few more). Each retry threads &lt;code&gt;previous_response_id&lt;/code&gt; — the Responses API handle that resumes from a prior turn's reasoning state — so the model continues from where it stopped instead of re-deriving its plan from scratch.&lt;/p&gt;

&lt;p&gt;This is the quietest piece of the harness and the easiest to undervalue. It does not show up in the score directly, but on the longer tasks a single run will reconnect several times, and without state-carrying retries each of those would cost a full re-plan.&lt;/p&gt;

&lt;h2&gt;
  
  
  Skill classification
&lt;/h2&gt;

&lt;p&gt;Claude Code and the Codex CLI both let users pre-load skill files for the model to draw on. Hookele does the same thing, but the routing is explicit: a 100-token codex-mini call reads the task instruction, sees the skill catalog (descriptions only, never bodies), and returns JSON like &lt;code&gt;{"skills": ["async_cancellation"]}&lt;/code&gt;. The matched skill's full Markdown body gets appended to the system prompt before the loop starts.&lt;/p&gt;

&lt;p&gt;The implementation is one f-string and one Responses API call:&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="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;responses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpt-5.1-codex-mini&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nb"&gt;input&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;role&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;user&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;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;prompt&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="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;format&lt;/span&gt;&lt;span class="sh"&gt;"&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;type&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;json_object&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}},&lt;/span&gt;
    &lt;span class="n"&gt;reasoning&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;effort&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;high&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;max_output_tokens&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;skills&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;skills&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A skill file is just Markdown with YAML front matter and a dense bullet list. &lt;code&gt;async-cancellation-safety&lt;/code&gt; is a dozen lines of asyncio gotchas (shield cleanup, await cancelled tasks with &lt;code&gt;return_exceptions=True&lt;/code&gt;, semaphore-gated tasks that never start under KeyboardInterrupt). &lt;code&gt;crack-7z-hash&lt;/code&gt; mostly tells the model that &lt;code&gt;hashcat -m 11600&lt;/code&gt; is the right mode for 7z archives — the kind of magic number a small model would otherwise burn iterations brute-forcing around.&lt;/p&gt;

&lt;p&gt;The catalog is a folder of senior-engineer notebook pages: asyncio semantics, hashcat mode tables, SQL optimization patterns, and similar. Skills are deliberately task-agnostic — the same notes would carry over to any benchmark in this space. Examples are in the repo.&lt;/p&gt;

&lt;p&gt;On tasks where a skill applies, trajectory logs visibly compress: the model goes from "explore the problem space" to "follow the playbook and verify" without intermediate flailing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Error recovery
&lt;/h2&gt;

&lt;p&gt;Hookele does not pattern-match stack traces or auto-retry commands. The recovery loop is intentionally dumb.&lt;/p&gt;

&lt;p&gt;When a command fails, its truncated output goes back to the model. If the model then stalls (produces text or another plan revision instead of doing something productive), I inject a single nudge: "Last command failed. Summary: ... Try an alternative and continue." The nudge fires at most once until the next successful non-plan tool call resets it.&lt;/p&gt;

&lt;p&gt;That is the entire recovery layer. The model is consistently better at deciding what to try next than any heuristic I wrote, including the heuristics I wrote and then deleted.&lt;/p&gt;

&lt;p&gt;Transport-level failures (broken pipes, TLS handshakes, &lt;code&gt;response.incomplete&lt;/code&gt;) get handled before the model sees them. Runtime failures (Harbor restart, merge conflicts in &lt;code&gt;apply_patch&lt;/code&gt;, &lt;code&gt;pip install&lt;/code&gt; blocked by PEP 668) get surfaced verbatim so the model can pivot.&lt;/p&gt;

&lt;h2&gt;
  
  
  The system prompt
&lt;/h2&gt;

&lt;p&gt;The prompt is sectioned by Task, Workflow, Tools, Build Heuristics, Documentation lookup, Editing, Verification, and Constraints — not a flat numbered list. Active skills get appended below Constraints. The one detail worth calling out: the iteration countdown ("5 steps left", "FINAL WARNING") is not in the system prompt at all. It is injected as user messages mid-loop, so the model actually feels the deadline approaching instead of reading about it once at the start and forgetting.&lt;/p&gt;

&lt;h2&gt;
  
  
  The numbers
&lt;/h2&gt;

&lt;p&gt;Methodology: 89 tasks, 5 runs each, one Hookele harness, GPT-5.1-Codex-Mini, default 60-iteration cap, run via Harbor. Rank and neighboring entries come from a May 14, 2026 leaderboard snapshot.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Perfect (5/5)&lt;/strong&gt;: 46 tasks, from &lt;code&gt;kv-store-grpc&lt;/code&gt; to &lt;code&gt;feal-differential-cryptanalysis&lt;/code&gt; to &lt;code&gt;sanitize-git-repo&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Partial (1–4/5)&lt;/strong&gt;: 16 tasks. &lt;code&gt;pytorch-model-cli&lt;/code&gt; at 80%, &lt;code&gt;large-scale-text-editing&lt;/code&gt; at 60%, &lt;code&gt;path-tracing&lt;/code&gt; at 20%.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero (0/5)&lt;/strong&gt;: 27 tasks.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A sample of what actually broke in the 0/5 set, pulled from trajectory logs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;compile-compcert&lt;/code&gt; and &lt;code&gt;make-doom-for-mips&lt;/code&gt; — both hit the 60-iteration cap babysitting build systems (opam/Coq for CompCert, cross-toolchains for Doom). Around step 25 the model loses track of which dependency loop it is in, and the remaining iterations evaporate on &lt;code&gt;apt&lt;/code&gt;/&lt;code&gt;dpkg&lt;/code&gt; debugging.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sam-cell-seg&lt;/code&gt; — the model correctly identified MobileSAM as the right approach and wrote the conversion script, but the SAM weights and module are not present in the container. It marked the task complete with "testing pending due to unavailable weights/module." An environment ceiling, not a planning failure.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;regex-chess&lt;/code&gt; — on step 12 the model deemed the task infeasible and called &lt;code&gt;task_complete&lt;/code&gt; with a summary explaining why regex alone cannot express castling, en passant, and legality. Whether it is actually infeasible or the model gave up too early is debatable; either way, the harness has no obvious lever here.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;extract-moves-from-video&lt;/code&gt; — the model refused: "I can't help with downloading or transcribing videos from YouTube." A safety heuristic triggered on the task description, before any technical attempt.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The failure modes are more varied than a single "too hard for the model" story: real long-horizon ceilings, a missing-dependency environment ceiling, a premature give-up, and an unrelated safety refusal. Skill injection does not help in any of these categories.&lt;/p&gt;

&lt;p&gt;The full per-task table is on the &lt;a href="https://www.tbench.ai/leaderboard/terminal-bench/2.0/hookele/0.0.1/gpt-5.1-codex-mini%40openai" rel="noopener noreferrer"&gt;Hookele leaderboard run&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where skills run out
&lt;/h2&gt;

&lt;p&gt;Skills cut down on exploration cost. They do not change what the model can do. If a task fundamentally needs GPU, reliable OCR, or many hours of careful multi-step debugging, no amount of prompt engineering will rescue it — the 0/5 catalog above is mostly that.&lt;/p&gt;

&lt;p&gt;Harness engineering can expose the model's capability more reliably, but it cannot manufacture capability that is not there. Small models are often leaving performance on the table because the harness around them is too noisy, too brittle, or too eager to help — and that is the part this post is really about.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cost and time
&lt;/h2&gt;

&lt;p&gt;API spend across the submitted trajectory logs was $27, summed from &lt;code&gt;final_metrics.total_cost_usd&lt;/code&gt;. Nine trajectories in the bundle did not include final cost metrics, so the cost number covers 436 of 445 trials. That still averages about 6 cents per recorded task run. The full 5-run sweep took roughly 35.4 hours start to finish.&lt;/p&gt;

&lt;p&gt;Per-task spread is wide. &lt;code&gt;fix-git&lt;/code&gt; finishes in under a minute for a fraction of a cent. &lt;code&gt;compile-compcert&lt;/code&gt; and &lt;code&gt;qemu-alpine-ssh&lt;/code&gt; can burn ten minutes and twenty cents each.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I would tell someone starting
&lt;/h2&gt;

&lt;p&gt;Four things kept coming back:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Delete before you add.&lt;/strong&gt; The improvements I trusted most came from removing scaffolding — planner, state machine, criteria extractor, wrapper tools — not adding it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Let the model handle errors.&lt;/strong&gt; Every failure-mode heuristic I wrote underperformed the version where I just show the failure to the model and nudge once if it stalls.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cheap pre-passes beat clever prompting.&lt;/strong&gt; A 100-token classifier plus a folder of Markdown files moved the score more clearly than any structured-output or prompt-engineering pass.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Design the harness against a smaller model.&lt;/strong&gt; If it only works when a frontier model papers over every rough edge, the harness is doing less than you think.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Code: &lt;a href="https://github.com/sady4850/hookele-agent" rel="noopener noreferrer"&gt;https://github.com/sady4850/hookele-agent&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I kept some implementation details out of this post for length; the repo has the harness code, patcher, and representative skill files.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>agents</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Conductor Joins the Cloud Coding Agent Rush: Remote AI Devs Leave the Laptop</title>
      <dc:creator>pickuma</dc:creator>
      <pubDate>Wed, 20 May 2026 08:51:20 +0000</pubDate>
      <link>https://forem.com/pickuma/conductor-joins-the-cloud-coding-agent-rush-remote-ai-devs-leave-the-laptop-27cl</link>
      <guid>https://forem.com/pickuma/conductor-joins-the-cloud-coding-agent-rush-remote-ai-devs-leave-the-laptop-27cl</guid>
      <description>&lt;p&gt;For about two years, "AI coding agent" meant something that ran next to your editor: a Copilot completion, a Cursor chat panel, a Claude Code session in your terminal. The work used your CPU, held your attention, and stopped when you closed the laptop. That assumption is breaking. A separate class of tools runs the agent on remote infrastructure instead — you describe a task, close the tab, and come back to a pull request. Conductor is the newest name moving in this direction, and it lands in a category that already includes background agents from Cursor, GitHub, OpenAI, and Google.&lt;/p&gt;

&lt;h2&gt;
  
  
  The agent leaves your laptop
&lt;/h2&gt;

&lt;p&gt;A cloud coding agent executes on a vendor's servers rather than your machine. You hand it a task — fix a failing test, migrate a module, draft an endpoint — through a web UI, a chat message, or a linked issue. It spins up an isolated sandbox, clones your repository, works through the task, and pushes a branch or opens a PR. You don't watch the edits land in your editor; you review the output.&lt;/p&gt;

&lt;p&gt;That sounds like a small plumbing change, but it shifts what you can reasonably ask for. An IDE assistant is interactive: fast, visible, and dependent on you staying in the loop. A remote agent is asynchronous: slower to finish any single task, but it doesn't need your attention while it runs and doesn't compete with your machine for memory or battery.&lt;/p&gt;

&lt;p&gt;A concrete version: you notice a flaky integration test on Friday afternoon. With an IDE assistant you would open the file and work through it interactively. With a cloud agent you describe the symptom, link the failing run, and close the tab — the fix shows up as a PR you review on Monday, having spent no local time on it.&lt;/p&gt;

&lt;p&gt;The field filled out fast. GitHub's Copilot coding agent takes an assigned issue and returns a PR. Cursor's background agents run a task remotely while you keep editing locally. OpenAI's Codex cloud agent and Google's Jules both work asynchronously against your GitHub repositories. Devin markets itself as an autonomous teammate. Anthropic runs Claude Code as a hosted web service alongside the CLI. Conductor — known for orchestrating several agents at once, each in its own isolated workspace — is extending that orchestration toward remote execution. The pitch is consistent across all of them: stop treating your laptop as the place the work happens.&lt;/p&gt;

&lt;h2&gt;
  
  
  What changes when the work runs remotely
&lt;/h2&gt;

&lt;p&gt;Moving the agent off your laptop is not just a hardware swap. It changes the unit of work you delegate and the way you supervise it. Three shifts matter most.&lt;/p&gt;

&lt;p&gt;Parallelism stops being a resource problem. Running five local agents means five processes competing for your CPU, your RAM, and your battery — in practice you run one and wait. Running five remote agents costs you nothing locally. Your machine becomes a dashboard rather than a worker, and you can fan a bug triage out across several tasks, then review each branch as it finishes instead of serially.&lt;/p&gt;

&lt;p&gt;Long-running work stops blocking you. A dependency upgrade that touches 30 files, or a refactor that takes 40 minutes, no longer locks the editor you need for everything else. You assign it before a meeting and review the PR after. Wall-clock time per task may be longer than a local run, but it overlaps with the rest of your day rather than consuming it.&lt;/p&gt;

&lt;p&gt;Collaboration gets a shared surface. Because the task and its output live in shared infrastructure, a teammate can inspect an agent's branch, leave review comments, or take it over the same way they would any pull request. You can trigger a task from a phone, a Slack thread, or an issue tracker — the work no longer depends on your specific dev environment being awake, which also means a handoff across time zones stops stalling on "it's on my other machine."&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A remote agent you aren't watching can spend 30 minutes confidently heading the wrong direction. The asynchronous model removes your token-by-token oversight, so a vague task description costs more — you discover the misread only when the PR arrives. Write the task like a spec: name the files, state the constraints, and define what "done" looks like.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Picking a cloud agent without locking yourself in
&lt;/h2&gt;

&lt;p&gt;The tools differ most in details that are easy to skip past in a demo. Check how the sandbox is provisioned — can the agent install your dependencies and run your real test suite, or does it work against a stripped-down environment? Check what crosses into the vendor's cloud: your repository, and any secrets you grant for builds or integration tests, are processed on third-party infrastructure. Check the pricing model, because per-task, usage-based, and per-seat plans reward very different workloads. And check the review path — an agent that opens clean, scoped PRs into your existing flow is far less disruptive than one that invents its own.&lt;/p&gt;

&lt;p&gt;Lock-in is the quiet risk. Because the task description is the real interface, a task written for one agent usually transfers to another. Keep your prompts in version control or an issue tracker rather than buried in a vendor UI, and switching costs stay low.&lt;/p&gt;

&lt;p&gt;Conductor's angle — orchestrating multiple agents rather than running one — is worth weighing here. If your work splits cleanly into independent chunks, an orchestrator that launches and tracks several remote agents at once can beat a single-agent tool. If you mostly delegate one task at a time, that coordination layer is overhead you don't need yet.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Start with a contained, low-stakes task — a flaky test, a small dependency bump, a docs fix — before you delegate anything on a critical path. You learn an agent's failure modes on work that is cheap to throw away.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you want to test the remote model without leaving an editor you already know, Cursor is a low-risk place to start: the same IDE for interactive edits, plus background agents for delegated tasks.&lt;/p&gt;

&lt;p&gt;The remote agent category is young, and Conductor's arrival is a signal more than a verdict. The question for tooling teams is shifting from "which assistant runs in my IDE" to "where does my agent work run, and who can pick it up" — and that is worth deciding deliberately rather than by default.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://pickuma.com/posts/conductor-cloud-coding-agent-rush/?utm_source=devto&amp;amp;utm_medium=crosspost&amp;amp;utm_campaign=blog" rel="noopener noreferrer"&gt;pickuma.com&lt;/a&gt;. Subscribe to &lt;a href="https://pickuma.com/rss.xml" rel="noopener noreferrer"&gt;the RSS&lt;/a&gt; or follow &lt;a href="https://bsky.app/profile/pickuma.bsky.social" rel="noopener noreferrer"&gt;@pickuma.bsky.social&lt;/a&gt; for new reviews.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>tutorial</category>
      <category>productivity</category>
    </item>
    <item>
      <title>CI/CD avec GitHub Actions</title>
      <dc:creator>Ulrich (Houngbe)</dc:creator>
      <pubDate>Wed, 20 May 2026 08:50:45 +0000</pubDate>
      <link>https://forem.com/ulrich_houngbe_21e53b96/cicd-avec-github-actions-3hjo</link>
      <guid>https://forem.com/ulrich_houngbe_21e53b96/cicd-avec-github-actions-3hjo</guid>
      <description>&lt;h1&gt;
  
  
  CI/CD avec GitHub Actions : Guide Complet
&lt;/h1&gt;

&lt;p&gt;GitHub Actions révolutionne l'intégration et le déploiement continus en intégrant directement ces fonctionnalités dans votre repository GitHub. Ce guide vous accompagne dans la mise en place d'une pipeline CI/CD robuste.&lt;/p&gt;

&lt;h2&gt;
  
  
  Qu'est-ce que GitHub Actions ?
&lt;/h2&gt;

&lt;p&gt;GitHub Actions est une plateforme d'automatisation qui permet de :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Exécuter des workflows basés sur des événements&lt;/li&gt;
&lt;li&gt;Automatiser les tests, builds et déploiements&lt;/li&gt;
&lt;li&gt;Créer des actions personnalisées réutilisables&lt;/li&gt;
&lt;li&gt;S'intégrer parfaitement avec l'écosystème GitHub&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Concepts Fondamentaux
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Composants Clés
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Workflow&lt;/strong&gt; : Processus automatisé défini dans un fichier YAML&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Job&lt;/strong&gt; : Ensemble de steps qui s'exécutent sur un runner&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Step&lt;/strong&gt; : Action individuelle (commande ou action)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Runner&lt;/strong&gt; : Machine virtuelle qui exécute les jobs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Action&lt;/strong&gt; : Application réutilisable qui effectue une tâche&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Structure d'un Workflow
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;CI/CD Pipeline&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;develop&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup Node.js&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;18'&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install dependencies&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm ci&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run tests&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Pipeline CI Complète
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Workflow Python avec Tests
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Python CI&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;develop&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;lint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Set up Python&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-python@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;python-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.11'&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Cache pip dependencies&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/cache@v3&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;~/.cache/pip&lt;/span&gt;
          &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}&lt;/span&gt;
          &lt;span class="na"&gt;restore-keys&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
            &lt;span class="s"&gt;${{ runner.os }}-pip-&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install dependencies&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;python -m pip install --upgrade pip&lt;/span&gt;
          &lt;span class="s"&gt;pip install flake8 black mypy&lt;/span&gt;
          &lt;span class="s"&gt;pip install -r requirements.txt&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Lint with flake8&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics&lt;/span&gt;
          &lt;span class="s"&gt;flake8 . --count --exit-zero --max-complexity=10 --max-line-length=88 --statistics&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Format check with black&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;black --check .&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Type check with mypy&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mypy src/&lt;/span&gt;

  &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;needs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;lint&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;matrix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;python-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.9'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.10'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.11'&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

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

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Set up Python ${{ matrix.python-version }}&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-python@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;python-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ matrix.python-version }}&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install dependencies&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;python -m pip install --upgrade pip&lt;/span&gt;
          &lt;span class="s"&gt;pip install pytest pytest-cov&lt;/span&gt;
          &lt;span class="s"&gt;pip install -r requirements.txt&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run tests with coverage&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;pytest --cov=src --cov-report=xml --cov-report=html&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Upload coverage to Codecov&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;codecov/codecov-action@v3&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./coverage.xml&lt;/span&gt;
          &lt;span class="na"&gt;flags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unittests&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;codecov-umbrella&lt;/span&gt;

  &lt;span class="na"&gt;security&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run security scan&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pypa/gh-action-pip-audit@v1.0.8&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;requirements.txt&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run Bandit security check&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;pip install bandit&lt;/span&gt;
          &lt;span class="s"&gt;bandit -r src/ -f json -o bandit-report.json&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Upload security report&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/upload-artifact@v4&lt;/span&gt;
        &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;always()&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;security-report&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bandit-report.json&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Workflow Node.js/React
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Node.js CI/CD&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

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

    &lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;matrix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;16&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;18&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;20&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

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

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Use Node.js ${{ matrix.node-version }}&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ matrix.node-version }}&lt;/span&gt;
          &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;npm'&lt;/span&gt;

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

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run linting&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run lint&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run type checking&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run type-check&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run unit tests&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm test -- --coverage --watchAll=false&lt;/span&gt;

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

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

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Upload build artifacts&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/upload-artifact@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build-files-${{ matrix.node-version }}&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dist/&lt;/span&gt;

  &lt;span class="na"&gt;e2e-tests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;needs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;

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

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup Node.js&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;18'&lt;/span&gt;
          &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;npm'&lt;/span&gt;

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

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install Playwright&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npx playwright install --with-deps&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Start application&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;npm run build&lt;/span&gt;
          &lt;span class="s"&gt;npm run start &amp;amp;&lt;/span&gt;
          &lt;span class="s"&gt;sleep 30&lt;/span&gt;

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

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Upload test results&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/upload-artifact@v4&lt;/span&gt;
        &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;always()&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;playwright-report&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;playwright-report/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Pipeline CD avec Déploiement
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Déploiement sur AWS
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy to AWS&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;workflow_dispatch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

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

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

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Configure AWS credentials&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws-actions/configure-aws-credentials@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;aws-access-key-id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.AWS_ACCESS_KEY_ID }}&lt;/span&gt;
          &lt;span class="na"&gt;aws-secret-access-key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.AWS_SECRET_ACCESS_KEY }}&lt;/span&gt;
          &lt;span class="na"&gt;aws-region&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;us-east-1&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup Node.js&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;18'&lt;/span&gt;
          &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;npm'&lt;/span&gt;

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

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build application&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run build&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;REACT_APP_API_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.API_URL }}&lt;/span&gt;
          &lt;span class="na"&gt;REACT_APP_ENV&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;production&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy to S3&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;aws s3 sync dist/ s3://${{ secrets.S3_BUCKET }} --delete&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Invalidate CloudFront&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;aws cloudfront create-invalidation \&lt;/span&gt;
            &lt;span class="s"&gt;--distribution-id ${{ secrets.CLOUDFRONT_DISTRIBUTION_ID }} \&lt;/span&gt;
            &lt;span class="s"&gt;--paths "/*"&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Notify Slack&lt;/span&gt;
        &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;always()&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;8398a7/action-slack@v3&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ job.status }}&lt;/span&gt;
          &lt;span class="na"&gt;channel&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;#deployments'&lt;/span&gt;
          &lt;span class="na"&gt;webhook_url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.SLACK_WEBHOOK_URL }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Déploiement Docker
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Docker Build and Deploy&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;v*'&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;REGISTRY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ghcr.io&lt;/span&gt;
  &lt;span class="na"&gt;IMAGE_NAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ github.repository }}&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build-and-push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;read&lt;/span&gt;
      &lt;span class="na"&gt;packages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&lt;/span&gt;

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

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Set up Docker Buildx&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker/setup-buildx-action@v3&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Log in to Container Registry&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker/login-action@v3&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;registry&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ env.REGISTRY }}&lt;/span&gt;
          &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ github.actor }}&lt;/span&gt;
          &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.GITHUB_TOKEN }}&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Extract metadata&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;meta&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker/metadata-action@v5&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;images&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}&lt;/span&gt;
          &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
            &lt;span class="s"&gt;type=ref,event=branch&lt;/span&gt;
            &lt;span class="s"&gt;type=ref,event=pr&lt;/span&gt;
            &lt;span class="s"&gt;type=semver,pattern={{version}}&lt;/span&gt;
            &lt;span class="s"&gt;type=semver,pattern={{major}}.{{minor}}&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build and push Docker image&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker/build-push-action@v5&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
          &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
          &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ steps.meta.outputs.tags }}&lt;/span&gt;
          &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ steps.meta.outputs.labels }}&lt;/span&gt;
          &lt;span class="na"&gt;cache-from&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;type=gha&lt;/span&gt;
          &lt;span class="na"&gt;cache-to&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;type=gha,mode=max&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy to staging&lt;/span&gt;
        &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;github.ref == 'refs/heads/main'&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;echo "Deploying to staging environment"&lt;/span&gt;
          &lt;span class="s"&gt;# Commandes de déploiement ici&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Workflows Avancés
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Matrix Strategy avec Conditions
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Cross-platform Testing&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;fail-fast&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
      &lt;span class="na"&gt;matrix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;os&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;ubuntu-latest&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;windows-latest&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;macos-latest&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
        &lt;span class="na"&gt;python-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.9'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.10'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.11'&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
        &lt;span class="na"&gt;exclude&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;os&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;windows-latest&lt;/span&gt;
            &lt;span class="na"&gt;python-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.9'&lt;/span&gt;

    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ matrix.os }}&lt;/span&gt;

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

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Set up Python ${{ matrix.python-version }}&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-python@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;python-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ matrix.python-version }}&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install dependencies (Unix)&lt;/span&gt;
        &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;runner.os != 'Windows'&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;python -m pip install --upgrade pip&lt;/span&gt;
          &lt;span class="s"&gt;pip install -r requirements.txt&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install dependencies (Windows)&lt;/span&gt;
        &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;runner.os == 'Windows'&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;python -m pip install --upgrade pip&lt;/span&gt;
          &lt;span class="s"&gt;pip install -r requirements.txt&lt;/span&gt;
        &lt;span class="na"&gt;shell&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cmd&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run tests&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pytest&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Déploiement Multi-Environnement
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Multi-Environment Deploy&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;develop&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;deploy-staging&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;github.ref == 'refs/heads/develop'&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;staging&lt;/span&gt;
      &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://staging.example.com&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy to Staging&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;echo "Deploying to staging"&lt;/span&gt;
          &lt;span class="s"&gt;# Logique de déploiement staging&lt;/span&gt;

  &lt;span class="na"&gt;deploy-production&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;github.ref == 'refs/heads/main'&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;production&lt;/span&gt;
      &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://example.com&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy to Production&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;echo "Deploying to production"&lt;/span&gt;
          &lt;span class="s"&gt;# Logique de déploiement production&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Actions Personnalisées
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Action Composite
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# .github/actions/setup-node-cache/action.yml&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Setup&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Node&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;with&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Cache'&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Setup&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Node.js&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;with&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;dependency&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;caching'&lt;/span&gt;

&lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Node.js&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;version'&lt;/span&gt;
    &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
    &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;18'&lt;/span&gt;
  &lt;span class="na"&gt;working-directory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Working&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;directory'&lt;/span&gt;
    &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
    &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;.'&lt;/span&gt;

&lt;span class="na"&gt;runs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;using&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;composite'&lt;/span&gt;
  &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup Node.js&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v4&lt;/span&gt;
      &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ inputs.node-version }}&lt;/span&gt;
        &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;npm'&lt;/span&gt;
        &lt;span class="na"&gt;cache-dependency-path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ inputs.working-directory }}/package-lock.json&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install dependencies&lt;/span&gt;
      &lt;span class="na"&gt;working-directory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ inputs.working-directory }}&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm ci&lt;/span&gt;
      &lt;span class="na"&gt;shell&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bash&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Usage de l'Action
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup Node.js with cache&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./.github/actions/setup-node-cache&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;18'&lt;/span&gt;
          &lt;span class="na"&gt;working-directory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;./frontend'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Bonnes Pratiques
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Sécurité
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Utilisation des secrets&lt;/span&gt;
&lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy with secrets&lt;/span&gt;
    &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;API_KEY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.API_KEY }}&lt;/span&gt;
      &lt;span class="na"&gt;DB_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.DB_PASSWORD }}&lt;/span&gt;
    &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;echo "API_KEY is set: ${API_KEY:+yes}"&lt;/span&gt;
      &lt;span class="s"&gt;# Utiliser les secrets de manière sécurisée&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Optimisation des Performances
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Cache des dépendances&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Cache dependencies&lt;/span&gt;
  &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/cache@v3&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;~/.npm&lt;/span&gt;
      &lt;span class="s"&gt;node_modules&lt;/span&gt;
    &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}&lt;/span&gt;
    &lt;span class="na"&gt;restore-keys&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;${{ runner.os }}-npm-&lt;/span&gt;

&lt;span class="c1"&gt;# Parallélisation des jobs&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;lint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
  &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;needs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;lint&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Monitoring et Notifications
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Notify on failure&lt;/span&gt;
    &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;failure()&lt;/span&gt;
    &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/github-script@v7&lt;/span&gt;
    &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
        &lt;span class="s"&gt;github.rest.issues.createComment({&lt;/span&gt;
          &lt;span class="s"&gt;issue_number: context.issue.number,&lt;/span&gt;
          &lt;span class="s"&gt;owner: context.repo.owner,&lt;/span&gt;
          &lt;span class="s"&gt;repo: context.repo.repo,&lt;/span&gt;
          &lt;span class="s"&gt;body: '❌ Pipeline failed! Please check the logs.'&lt;/span&gt;
        &lt;span class="s"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;GitHub Actions offre une solution puissante et flexible pour l'automatisation :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Intégration native&lt;/strong&gt; avec GitHub&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Écosystème riche&lt;/strong&gt; d'actions réutilisables&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scaling automatique&lt;/strong&gt; des runners&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Support multi-plateforme&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Gestion fine des permissions&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Une pipeline bien conçue améliore la qualité du code, réduit les risques de déploiement et accélère le cycle de développement. L'investissement initial en configuration est rapidement rentabilisé par la réduction des erreurs et l'automatisation des tâches répétitives.&lt;/p&gt;

</description>
      <category>cicd</category>
      <category>devops</category>
    </item>
    <item>
      <title>kop — A Modern Kubernetes Terminal UI Built with Python</title>
      <dc:creator>vegaoqiang</dc:creator>
      <pubDate>Wed, 20 May 2026 08:49:16 +0000</pubDate>
      <link>https://forem.com/vegaoqiang/kop-a-modern-kubernetes-terminal-ui-built-with-python-3f49</link>
      <guid>https://forem.com/vegaoqiang/kop-a-modern-kubernetes-terminal-ui-built-with-python-3f49</guid>
      <description>&lt;p&gt;I spend most of my day managing Kubernetes clusters from the terminal.&lt;br&gt;
Like many engineers, I rely heavily on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;kubectl&lt;/li&gt;
&lt;li&gt;SSH&lt;/li&gt;
&lt;li&gt;log streaming&lt;/li&gt;
&lt;li&gt;pod debugging&lt;/li&gt;
&lt;li&gt;cluster troubleshooting&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Over time, I realized I wanted something that felt more interactive and efficient than constantly switching between terminal commands and browser dashboards.&lt;/p&gt;

&lt;p&gt;So I started building kop.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is kop?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fvegaoqiang%2Fkop%2Frefs%2Fheads%2Fmain%2Fdocs%2Fimages%2Fsample.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fvegaoqiang%2Fkop%2Frefs%2Fheads%2Fmain%2Fdocs%2Fimages%2Fsample.png" alt="heroicon" width="799" height="286"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;kop is a modern terminal UI for Kubernetes built with Python.&lt;br&gt;
It provides an interactive Kubernetes experience directly inside the terminal while remaining lightweight, keyboard-driven, and SSH-friendly.&lt;/p&gt;

&lt;p&gt;Project site:&lt;/p&gt;

&lt;p&gt;&lt;a&gt;GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://vegaoqiang.github.io/kop/" rel="noopener noreferrer"&gt;kop Documentation&lt;/a&gt;￼&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Another Kubernetes TUI?
&lt;/h2&gt;

&lt;p&gt;Tools like K9s￼are already excellent.But while using existing tools, I still wanted:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A cleaner modern UI&lt;/li&gt;
&lt;li&gt;Better keyboard workflows&lt;/li&gt;
&lt;li&gt;Faster navigation&lt;/li&gt;
&lt;li&gt;More extensible architecture&lt;/li&gt;
&lt;li&gt;Improved terminal interaction&lt;/li&gt;
&lt;li&gt;A smoother troubleshooting experience&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;kop is my attempt to explore those ideas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Features
&lt;/h2&gt;

&lt;p&gt;Interactive Kubernetes Resource Navigation&lt;br&gt;
Browse resources interactively:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pods&lt;/li&gt;
&lt;li&gt;Deployments&lt;/li&gt;
&lt;li&gt;StatefulSets&lt;/li&gt;
&lt;li&gt;DaemonSets&lt;/li&gt;
&lt;li&gt;Services&lt;/li&gt;
&lt;li&gt;Nodes&lt;/li&gt;
&lt;li&gt;Namespaces&lt;/li&gt;
&lt;li&gt;ConfigMaps&lt;/li&gt;
&lt;li&gt;Secrets&lt;/li&gt;
&lt;li&gt;Events&lt;/li&gt;
&lt;li&gt;...&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Screenshots
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr89xl6vuqw0qwczzg23e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr89xl6vuqw0qwczzg23e.png" alt=" " width="800" height="477"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>python</category>
      <category>tui</category>
      <category>opensource</category>
    </item>
    <item>
      <title>CLI ile Aracı Token Maliyetlerini Düşürme (2026 Rehberi)</title>
      <dc:creator>Tobias Hoffmann</dc:creator>
      <pubDate>Wed, 20 May 2026 08:46:49 +0000</pubDate>
      <link>https://forem.com/tobiass_hoffmann/cli-ile-araci-token-maliyetlerini-dusurme-2026-rehberi-5fep</link>
      <guid>https://forem.com/tobiass_hoffmann/cli-ile-araci-token-maliyetlerini-dusurme-2026-rehberi-5fep</guid>
      <description>&lt;p&gt;Bir CLI kodlama ajanı, fatura gelene kadar “özgür” görünür. Claude Code veya Codex’i bir depoya yönlendirip bir modülü yeniden düzenlemesini istediğinizde, on dakika içinde kırk dosya okumuş, testleri üç kez çalıştırmış ve aslında hiç gerek olmayan bağlam için altı haneli token harcamış olabilir. Bunu gün boyu ajan kullanan sekiz kişilik bir ekiple çarptığınızda maliyet hızla büyür. İyi haber: Kodlama ajanlarında token israfının büyük kısmı, modeli değiştirmeden veya çıktı kalitesinden vazgeçmeden komut satırı alışkanlıklarıyla azaltılabilir.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://apidog.com/?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation" class="crayons-btn crayons-btn--primary"&gt;Apidog'u bugün deneyin&lt;/a&gt;
&lt;/p&gt;

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

&lt;p&gt;Ajan maliyetini düşürmek için modele gitmeden önce bağlamı küçültün:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Çalışma kümesini dosya/dizin bazında sınırlayın.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CLAUDE.md&lt;/code&gt; gibi bellek dosyalarını kısa tutun.&lt;/li&gt;
&lt;li&gt;Uzun oturumlarda &lt;code&gt;/compact&lt;/code&gt; veya &lt;code&gt;/clear&lt;/code&gt; kullanın.&lt;/li&gt;
&lt;li&gt;Kararlı ön ekler için istem önbellekleme açın.&lt;/li&gt;
&lt;li&gt;Basit alt görevleri daha ucuz modele yönlendirin.&lt;/li&gt;
&lt;li&gt;Test, kurulum ve diff çıktısını filtreleyin.&lt;/li&gt;
&lt;li&gt;Her çalıştırmanın token ve maliyetini ölçün.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Giriş
&lt;/h2&gt;

&lt;p&gt;Sorun genelde iki şekilde görünür: Ya görev ortasında haftalık/oturum limitine çarparsınız ya da ay sonunda API faturası gelir ve “AI asistanı neden bu kadar pahalı?” sorusu sorulur.&lt;/p&gt;

&lt;p&gt;Temel neden aynıdır: CLI ajanları varsayılan olarak çok fazla bağlam taşır. On satır koda ihtiyaç duyduklarında tüm dosyayı okurlar, her dönüşte konuşma geçmişini yeniden gönderirler, komut çıktılarını ham haliyle bağlama eklerler ve aynı sistem istemini binlerce kez tekrar yollarlar.&lt;/p&gt;

&lt;p&gt;Bu kaçınılmaz değildir. 2.000 token’lık kod üzerinde akıl yürütmesi gereken bir refactor işleminin 180.000 token bağlama ihtiyacı yoktur. Aradaki fark sizin tasarruf alanınızdır.&lt;/p&gt;

&lt;p&gt;Bu rehberde şu başlıkları uygulamalı olarak ele alacağız:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CLI ajan çalışmasında token’ların nereye gittiği&lt;/li&gt;
&lt;li&gt;Bağlam hijyeni ve bellek dosyaları&lt;/li&gt;
&lt;li&gt;İstem önbellekleme&lt;/li&gt;
&lt;li&gt;Model yönlendirme&lt;/li&gt;
&lt;li&gt;Araç çıktısını ve dosya alımını kısaltma&lt;/li&gt;
&lt;li&gt;Çalıştırma başına maliyet ölçümü&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Örnekler Claude Code ve Codex üzerinden ilerliyor, ancak aynı ilkeler token tabanlı API kullanan çoğu kodlama ajanı için geçerlidir.&lt;/p&gt;

&lt;p&gt;Ek bir maliyet kaynağı da API hata ayıklamasıdır. Güvenilmez bir dahili API’ye bağlanan ajan, her denemede token harcar: yeniden dener, hata gövdelerini okur, belgeleri tekrar tarar ve aynı döngüye girer.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 Ajanlarınız API’lerle çalışıyorsa, API’leri ajana vermeden önce Apidog’da tasarlamak, mock verilerle test etmek ve sözleşmesini doğrulamak pahalı deneme-yanılma döngülerini azaltır. Ajan, sürprizlerle dolu canlı bir endpoint yerine beklenen davranışı olan bir API sözleşmesine karşı çalışır.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  CLI Ajan Çalışmasında Token’lar Nereye Gider?
&lt;/h2&gt;

&lt;p&gt;Bir ajan dönüşünde modele giriş yükü gönderilir ve modelden çıktı alınır. İkisi için de ödeme yaparsınız. Çoğu sağlayıcıda çıktı token’ları, giriş token’larından daha pahalıdır.&lt;/p&gt;

&lt;p&gt;Örnek olarak bir model ailesinde:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Giriş: milyon token başına yaklaşık 3$&lt;/li&gt;
&lt;li&gt;Çıkış: milyon token başına yaklaşık 15$&lt;/li&gt;
&lt;li&gt;Daha küçük modelde giriş: yaklaşık 1$&lt;/li&gt;
&lt;li&gt;Daha küçük modelde çıkış: yaklaşık 5$&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Bunları sabit fiyat olarak değil, oranları anlamak için örnek kabul edin. Güncel fiyatları her zaman sağlayıcının fiyatlandırma sayfasından kontrol edin.&lt;/p&gt;

&lt;p&gt;Tipik bir ajan çalışmasında giriş token’larını büyüten kalemler şunlardır:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sistem istemi ve araç tanımları:&lt;/strong&gt; Ajan talimatları ve araç JSON şemaları. Her dönüşte tekrar gönderilir.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bellek/proje dosyaları:&lt;/strong&gt; &lt;code&gt;CLAUDE.md&lt;/code&gt; gibi dosyalar, depo kuralları ve kalıcı talimatlar.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Konuşma geçmişi:&lt;/strong&gt; Önceki kullanıcı mesajları, model yanıtları, araç çağrıları ve araç sonuçları.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Okunan dosya içerikleri:&lt;/strong&gt; Ajanın açtığı kaynak dosyalar.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Araç çıktısı:&lt;/strong&gt; Test logları, &lt;code&gt;npm install&lt;/code&gt; çıktısı, &lt;code&gt;git diff&lt;/code&gt;, stack trace’ler.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;En kritik nokta: &lt;strong&gt;Konuşma geçmişi her dönüşte yeniden oynatılır.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;30 dönüşlük bir oturum, tek dönüşün 30 katı değildir; büyüyen bir ön ekin tekrar tekrar gönderilmesine benzer. Bu yüzden uzun ve dağınık oturumlar pahalıdır.&lt;/p&gt;

&lt;p&gt;Oturum ve limit muhasebesi hakkında daha fazla detay için &lt;a href="http://apidog.com/blog/claude-code-token-window-reset?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;Claude Code token penceresinin nasıl sıfırlandığına&lt;/a&gt; dair açıklama faydalı bir tamamlayıcıdır.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Bağlam Hijyeni ve Bellek Dosyaları
&lt;/h2&gt;

&lt;p&gt;En ucuz token, hiç göndermediğiniz tokendir.&lt;/p&gt;

&lt;h3&gt;
  
  
  Çalışma kümesini baştan sınırlayın
&lt;/h3&gt;

&lt;p&gt;Ajanı depo kökünde açıp şunu demeyin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude &lt;span class="s2"&gt;"fatura mantığını yeniden düzenle"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bu, ajanın gereksiz keşif yapmasına yol açar.&lt;/p&gt;

&lt;p&gt;Bunun yerine dosya ve kapsam belirtin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude &lt;span class="s2"&gt;"src/payments/retry.ts ve ilgili test dosyasında üstel geri çekilmeyi kullanacak şekilde yeniden deneme mantığını yeniden düzenle"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Daha iyi bir istem şunları içerir:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Değiştirilecek dosyalar&lt;/li&gt;
&lt;li&gt;Değişiklik hedefi&lt;/li&gt;
&lt;li&gt;Test kapsamı&lt;/li&gt;
&lt;li&gt;Okunmaması gereken alanlar&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Örnek:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude &lt;span class="s2"&gt;"
Sadece şu dosyaları kullan:
- src/payments/retry.ts
- src/payments/retry.test.ts

Amaç:
Yeniden deneme mantığını üstel geri çekilme kullanacak şekilde düzenle.

Kısıtlar:
- Public API imzasını değiştirme.
- Başka dizinleri tarama.
- Sadece başarısız testleri çalıştır.
"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Bellek dosyasını kısa tutun
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;CLAUDE.md&lt;/code&gt; veya eşdeğer proje bellek dosyası her dönüşte bağlama eklenebilir. Bu dosya büyüdükçe her ajan çağrısının sabit maliyeti artar.&lt;/p&gt;

&lt;p&gt;Yaklaşık token sayısını kontrol edin:&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;wc&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; CLAUDE.md | &lt;span class="nb"&gt;awk&lt;/span&gt; &lt;span class="s1"&gt;'{print "≈", int($1/4), "token/dönüş"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;İyi bir &lt;code&gt;CLAUDE.md&lt;/code&gt; şunları içermelidir:&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;# Proje Kuralları&lt;/span&gt;

&lt;span class="gu"&gt;## Komutlar&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; Test: npm test --silent
&lt;span class="p"&gt;-&lt;/span&gt; Lint: npm run lint
&lt;span class="p"&gt;-&lt;/span&gt; Typecheck: npm run typecheck

&lt;span class="gu"&gt;## Kod Kuralları&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; Public API imzalarını değiştirme.
&lt;span class="p"&gt;-&lt;/span&gt; Yeni bağımlılık eklemeden önce sor.
&lt;span class="p"&gt;-&lt;/span&gt; Test eklemeden refactor tamamlanmış sayılmaz.

&lt;span class="gu"&gt;## Belgeler&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; API sözleşmeleri: docs/api.md
&lt;span class="p"&gt;-&lt;/span&gt; Ödeme akışı: docs/payments.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Kötü örnek:&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;# Proje Hakkında&lt;/span&gt;

Bu proje 2021 yılında başladı...
Burada tüm mimari geçmişi...
Tüm endpoint belgeleri...
Tüm veritabanı tabloları...
Tüm onboarding notları...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bellek dosyası wiki değildir. Sık kullanılan kuralları tutun, detaylı belgeleri linkleyin.&lt;/p&gt;

&lt;h3&gt;
  
  
  Uzun oturumları sıkıştırın veya temizleyin
&lt;/h3&gt;

&lt;p&gt;Bir görev bittiğinde aynı konuşma içinde yeni göreve geçmeyin. Eski bağlam yeni görevin maliyetini artırır.&lt;/p&gt;

&lt;p&gt;Claude Code’da:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Bu, geçmişi kısa bir özete dönüştürür.&lt;/p&gt;

&lt;p&gt;Yeni ve ilgisiz bir göreve başlıyorsanız:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Basit kural:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Aynı mantıksal görev: devam edin.&lt;/li&gt;
&lt;li&gt;Yeni görev: &lt;code&gt;/compact&lt;/code&gt; veya &lt;code&gt;/clear&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="http://apidog.com/blog/claude-code-workflows?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;Claude Code iş akışlarındaki&lt;/a&gt; desenler bu kapsam belirleme alışkanlığına dayanır.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ignore dosyası kullanın
&lt;/h3&gt;

&lt;p&gt;Ajanın şu dizinleri okumasını engelleyin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node_modules/
dist/
build/
coverage/
.next/
.vendor/
*.lock
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ajan &lt;code&gt;node_modules/&lt;/code&gt; veya &lt;code&gt;dist/&lt;/code&gt; görmezse, bu dosyaları okuyup token harcayamaz.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. İstem Önbellekleme: Aynı Ön Ek İçin Tekrar Ödeme Yapmayın
&lt;/h2&gt;

&lt;p&gt;İstem önbellekleme, sistem istemi, araç tanımları ve depo kuralları gibi kararlı ön eklerin sağlayıcı tarafından önbelleğe alınmasını sağlar.&lt;/p&gt;

&lt;p&gt;Ekonomi basittir:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;İlk yazma normal girişten biraz pahalıdır.&lt;/li&gt;
&lt;li&gt;Sonraki okumalar yaklaşık %90 indirimlidir.&lt;/li&gt;
&lt;li&gt;Büyük ve sabit ön eklerde ciddi tasarruf sağlar.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Kararlı içeriği önce, değişken içeriği sonra koyun:&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="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;claude-sonnet-4-6&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;max_tokens&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2048&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;system&lt;/span&gt;&lt;span class="o"&gt;=&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;type&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;text&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;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;SYSTEM_PROMPT&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;REPO_CONVENTIONS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cache_control&lt;/span&gt;&lt;span class="sh"&gt;"&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;type&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;ephemeral&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&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;role&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;user&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;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;user_task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Kullanımı ölçün:&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="n"&gt;u&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;usage&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;önbellek yazma:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cache_creation_input_tokens&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;önbellek okuma :&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cache_read_input_tokens&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;yeni giriş     :&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;input_tokens&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dikkat edilmesi gerekenler:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Önbellek kesme noktasından önce değişken veri koymayın.&lt;/li&gt;
&lt;li&gt;Sistem istemine timestamp eklemeyin.&lt;/li&gt;
&lt;li&gt;Aynı işleri yakın zaman aralığında çalıştırın.&lt;/li&gt;
&lt;li&gt;Ön ek bayt düzeyinde kararlı olmalıdır.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Örnek senaryo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sistem istemi + repo kuralları: 8.000 token&lt;/li&gt;
&lt;li&gt;Günlük çağrı sayısı: 60&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Önbellekleme yoksa 8.000 token için 60 kez ödeme yaparsınız. Önbellekleme varsa ilk yazmadan sonra çoğu çağrı indirimli okunur.&lt;/p&gt;

&lt;p&gt;OpenAI tarafında da desteklenen modellerde önbelleğe alınmış giriş için benzer indirimler otomatik uygulanabilir. Ayarlar değişebilir, ancak ilke aynıdır.&lt;/p&gt;

&lt;p&gt;Codex tarafında yönlendirme ve ücretsiz katman seçenekleri için &lt;a href="http://apidog.com/blog/how-to-use-gpt-5-5-free-codex?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;Codex aracılığıyla GPT-5.5’i ücretsiz çalıştırma&lt;/a&gt; rehberi bu stratejiyi tamamlar.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Model Yönlendirme: Basit İşe Ucuz Model
&lt;/h2&gt;

&lt;p&gt;Her görev en güçlü modeli gerektirmez.&lt;/p&gt;

&lt;p&gt;Şunlar genellikle küçük modelle yapılabilir:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Commit mesajı yazma&lt;/li&gt;
&lt;li&gt;Diff özetleme&lt;/li&gt;
&lt;li&gt;Changelog girdisi oluşturma&lt;/li&gt;
&lt;li&gt;Basit test taslağı üretme&lt;/li&gt;
&lt;li&gt;Değişken yeniden adlandırma&lt;/li&gt;
&lt;li&gt;Lint hatası açıklama&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Şunlar daha güçlü model gerektirebilir:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mimari karar&lt;/li&gt;
&lt;li&gt;Karmaşık refactor&lt;/li&gt;
&lt;li&gt;Çok dosyalı hata ayıklama&lt;/li&gt;
&lt;li&gt;Performans analizi&lt;/li&gt;
&lt;li&gt;Güvenlik açısından kritik değişiklik&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;CLI’dan model seçimi:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude &lt;span class="nt"&gt;--model&lt;/span&gt; haiku &lt;span class="s2"&gt;"evreye alınmış diff için conventional commit mesajı yaz"&lt;/span&gt;

claude &lt;span class="nt"&gt;--model&lt;/span&gt; sonnet &lt;span class="s2"&gt;"ödeme servisi için cache katmanını yeniden tasarla"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Varsayılan strateji:&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;# Basit görevler için ucuz model&lt;/span&gt;
&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;ccheap&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'claude --model haiku'&lt;/span&gt;

&lt;span class="c"&gt;# Zor görevler için güçlü model&lt;/span&gt;
&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;cstrong&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'claude --model sonnet'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Kullanım:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ccheap &lt;span class="s2"&gt;"bu diff'i 5 maddede özetle"&lt;/span&gt;

cstrong &lt;span class="s2"&gt;"src/payments içindeki retry ve idempotency akışını analiz et"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Çoğu ekip tersini yapar: Her şeyi pahalı modelle çalıştırır ve basit işler için gereksiz ödeme yapar.&lt;/p&gt;

&lt;p&gt;Alt-ajan destekleyen sistemlerde de aynı kural geçerlidir:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Üst ajan: güçlü model, küçük karar sayısı&lt;/li&gt;
&lt;li&gt;Alt ajan: ucuz model, dar görev, kısa bağlam&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Örneğin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Alt ajan görevi:
Sadece src/payments dizininde retry ile ilgili fonksiyonları bul.
Kod değiştirme.
En fazla 10 maddelik özet döndür.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Üst ajan sadece özetlenmiş sonucu görür; tüm arama bağlamını taşımak zorunda kalmaz.&lt;/p&gt;

&lt;p&gt;Bu yetki devri desenleri için &lt;a href="http://apidog.com/blog/goal-command-codex-claude-code-autonomous-agents?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;Codex ve Claude Code’daki hedef komut&lt;/a&gt; rehberindeki otonom döngü örnekleri faydalıdır.&lt;/p&gt;

&lt;p&gt;Limitli plan kullanıyorsanız model yönlendirme yalnızca maliyeti değil, hakkınızın ne kadar dayanacağını da etkiler. &lt;a href="http://apidog.com/blog/claude-code-weekly-limits-50-percent-increase-july-2026?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;Claude Code haftalık limit artışı&lt;/a&gt; yardımcı olabilir, ancak doğru yönlendirme hâlâ kritik kaldıraçtır.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Araç Çıktısını Kısaltın
&lt;/h2&gt;

&lt;p&gt;Ajanın çalıştırdığı her komut metin döndürür. Bu metin bağlama eklenir ve sonraki dönüşlerde tekrar gönderilir.&lt;/p&gt;

&lt;p&gt;Gürültülü komutlar pahalıdır:&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;npm &lt;span class="nb"&gt;install
&lt;/span&gt;git diff
pytest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Komutları sessiz çalıştırın
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Gürültülü&lt;/span&gt;
npm &lt;span class="nb"&gt;test&lt;/span&gt;

&lt;span class="c"&gt;# Daha kısa çıktı&lt;/span&gt;
npm &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;--silent&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nt"&gt;--reporter&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;dot
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Gürültülü&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt;

&lt;span class="c"&gt;# Daha kısa çıktı&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--silent&lt;/span&gt; &lt;span class="nt"&gt;--no-audit&lt;/span&gt; &lt;span class="nt"&gt;--no-fund&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Çıktıyı filtreleyin
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pytest &lt;span class="nt"&gt;-q&lt;/span&gt; 2&amp;gt;&amp;amp;1 | &lt;span class="nb"&gt;tail&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; 30
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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;/code&gt;&lt;/pre&gt;

&lt;/div&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;2&amp;gt;&amp;amp;1 | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s2"&gt;"(FAIL|✗|Error)"&lt;/span&gt; | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; 20
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ajan çoğu zaman tüm loga değil, şu bilgilere ihtiyaç duyar:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Test geçti mi?&lt;/li&gt;
&lt;li&gt;Hangi test başarısız oldu?&lt;/li&gt;
&lt;li&gt;Hata mesajı nedir?&lt;/li&gt;
&lt;li&gt;İlgili stack trace’in son kısmı nedir?&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Büyük diff’leri sınırlayın
&lt;/h3&gt;

&lt;p&gt;Şunu yaptırmayın:&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Önce özet alın:&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sonra yalnızca ilgili dosyayı açtırın:&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; src/payments/retry.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Kilit dosyaları özellikle tehlikelidir:&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; package-lock.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bu çıktı binlerce satır olabilir. Ajanın genelde tamamına ihtiyacı yoktur.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Tüm Dosya Yerine Hedefli Okuma Kullanın
&lt;/h2&gt;

&lt;p&gt;Bir fonksiyonu değiştirmek için 1.500 satırlık dosyanın tamamını okumak israftır.&lt;/p&gt;

&lt;p&gt;Daha iyi yaklaşım:&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;-n&lt;/span&gt; &lt;span class="s2"&gt;"function retryPayment"&lt;/span&gt; src/payments/retry.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sonra ilgili pencereyi okuyun:&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;sed&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s1"&gt;'120,220p'&lt;/span&gt; src/payments/retry.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ajan istemine bunu açıkça yazın:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Tüm dosyayı okuma.
Önce retry mantığını grep ile bul.
Sadece ilgili fonksiyonun çevresindeki yaklaşık 100 satırı oku.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Büyük dosyalarda bu fark ciddi olabilir:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tüm dosya: ~18.000 token&lt;/li&gt;
&lt;li&gt;Hedefli pencere: ~800 token&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  6. RAG ve Doküman Alımını Sınırlayın
&lt;/h2&gt;

&lt;p&gt;Ajanınız kod tabanı araması veya doküman RAG kullanıyorsa, alınan parçaların sayısı ve boyutu maliyeti doğrudan etkiler.&lt;/p&gt;

&lt;p&gt;Kötü varsayılan:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;top_k = 50
chunk_size = 800
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bu, modele 40.000 token’a yakın bağlam taşıyabilir.&lt;/p&gt;

&lt;p&gt;Daha iyi başlangıç:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;top_k = 8
chunk_size = 200
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pratik kural:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Daha az ama daha alakalı parça&lt;/li&gt;
&lt;li&gt;Kısa chunk&lt;/li&gt;
&lt;li&gt;Soruya göre filtrelenmiş dizin&lt;/li&gt;
&lt;li&gt;Gereksiz doküman koleksiyonlarını dışarıda bırakma&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Örnek istem:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Sadece docs/payments ve src/payments altında arama yap.
Genel README, changelog ve onboarding belgelerini kullanma.
En fazla 8 kısa sonuç döndür.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  7. Her Çalıştırmanın Maliyetini Ölçün
&lt;/h2&gt;

&lt;p&gt;Ölçmediğiniz maliyeti azaltamazsınız.&lt;/p&gt;

&lt;p&gt;API yanıtındaki kullanım bilgilerini kaydedin:&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="n"&gt;u&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;usage&lt;/span&gt;

&lt;span class="n"&gt;INPUT_RATE&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;3.00&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1_000_000&lt;/span&gt;
&lt;span class="n"&gt;OUTPUT_RATE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;15.00&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1_000_000&lt;/span&gt;
&lt;span class="n"&gt;CACHE_READ&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.30&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1_000_000&lt;/span&gt;
&lt;span class="n"&gt;CACHE_WRITE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;3.75&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1_000_000&lt;/span&gt;

&lt;span class="n"&gt;cost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;input_tokens&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;INPUT_RATE&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
    &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output_tokens&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;OUTPUT_RATE&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
    &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cache_read_input_tokens&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;CACHE_READ&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
    &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cache_creation_input_tokens&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;CACHE_WRITE&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="s"&gt;çalıştırma maliyeti ≈ $&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;cost&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;(girdi=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;input_tokens&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;çıktı=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output_tokens&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;önbellek okuma=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cache_read_input_tokens&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;CLI kullanıyorsanız:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Daha iyi izleme için ajan çağrısını küçük bir wrapper içine alın:&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="nv"&gt;TASK&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;START&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;-Iseconds&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

claude &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TASK&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="nv"&gt;END&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;-Iseconds&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$START&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;$END&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;$TASK&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; agent-runs.csv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Daha gelişmiş sürümde şunları da kaydedin:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Model&lt;/li&gt;
&lt;li&gt;Proje&lt;/li&gt;
&lt;li&gt;Görev etiketi&lt;/li&gt;
&lt;li&gt;Giriş token&lt;/li&gt;
&lt;li&gt;Çıkış token&lt;/li&gt;
&lt;li&gt;Cache read/write token&lt;/li&gt;
&lt;li&gt;Yaklaşık maliyet&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;API anahtarlarını da ayırın:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Proje başına anahtar&lt;/li&gt;
&lt;li&gt;Ajan türü başına anahtar&lt;/li&gt;
&lt;li&gt;Ortam başına anahtar&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Böylece harcama tek bir toplamda kaybolmaz.&lt;/p&gt;

&lt;h2&gt;
  
  
  Taktik Karşılaştırması
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Taktik&lt;/th&gt;
&lt;th&gt;Tipik token tasarrufu&lt;/th&gt;
&lt;th&gt;Çaba&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Çalışma kümesini sınırlama&lt;/td&gt;
&lt;td&gt;Çalıştırma başına girdide %30–60&lt;/td&gt;
&lt;td&gt;Düşük&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Kısa ve kararlı bellek dosyası&lt;/td&gt;
&lt;td&gt;Her dönüşte %5–15&lt;/td&gt;
&lt;td&gt;Düşük&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;/compact&lt;/code&gt; veya &lt;code&gt;/clear&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Uzun oturumlarda %40–80&lt;/td&gt;
&lt;td&gt;Düşük&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;İstem önbellekleme&lt;/td&gt;
&lt;td&gt;Önbelleğe alınan ön ekte ~%90&lt;/td&gt;
&lt;td&gt;Orta&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Model yönlendirme&lt;/td&gt;
&lt;td&gt;Yönlendirilen alt görevlerde %50–80&lt;/td&gt;
&lt;td&gt;Orta&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sessiz/filtrelenmiş araç çıktısı&lt;/td&gt;
&lt;td&gt;Araç yoğun çalıştırmalarda %20–50&lt;/td&gt;
&lt;td&gt;Düşük&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hedefli dosya okuma&lt;/td&gt;
&lt;td&gt;Büyük dosyalarda %70–95&lt;/td&gt;
&lt;td&gt;Düşük&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Kısıtlı RAG alımı&lt;/td&gt;
&lt;td&gt;RAG yoğun ajanlarda %30–60&lt;/td&gt;
&lt;td&gt;Orta&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Çalıştırma başına maliyet ölçümü&lt;/td&gt;
&lt;td&gt;Doğrudan %0; diğerlerini mümkün kılar&lt;/td&gt;
&lt;td&gt;Düşük&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Tasarruf oranları örnektir. Gerçek kazanç, mevcut israf seviyenize bağlıdır.&lt;/p&gt;

&lt;h2&gt;
  
  
  Uygulanabilir Kontrol Listesi
&lt;/h2&gt;

&lt;p&gt;Başlamak için sırayla şunları yapın:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[ ] CLAUDE.md dosyasını 1.000 token altına indir.
[ ] node_modules, dist, build, coverage ve lock dosyalarını ignore et.
[ ] Ajan istemlerinde dosya/dizin kapsamı belirt.
[ ] Test komutlarını sessiz moda al.
[ ] git diff yerine önce git diff --stat kullan.
[ ] Uzun oturumlarda /compact kullan.
[ ] Yeni görevlerde /clear ile başla.
[ ] Commit mesajı/diff özeti gibi işleri ucuz modele yönlendir.
[ ] Kararlı sistem istemi için prompt caching aç.
[ ] Her çalıştırma için token ve maliyet kaydı tut.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Sonuç
&lt;/h2&gt;

&lt;p&gt;Ajan token maliyetlerinin çoğu modelden değil, çalışma şeklinden kaynaklanır. Gereksiz bağlam, uzun konuşma geçmişi, ham araç çıktısı ve yanlış model seçimi faturayı büyütür.&lt;/p&gt;

&lt;p&gt;Önce düşük çabalı adımları uygulayın:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Kapsamı daraltın.&lt;/li&gt;
&lt;li&gt;Bellek dosyasını küçültün.&lt;/li&gt;
&lt;li&gt;Araç çıktısını sessizleştirin.&lt;/li&gt;
&lt;li&gt;Uzun oturumları temizleyin.&lt;/li&gt;
&lt;li&gt;Basit işleri ucuz modele taşıyın.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ardından istem önbellekleme ve maliyet ölçümü ekleyin. Bu kombinasyon, çıktı kalitesini düşürmeden ajan maliyetlerini yönetilebilir hale getirir.&lt;/p&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>cli</category>
      <category>productivity</category>
    </item>
    <item>
      <title>วิธีลดค่าใช้จ่ายโทเค็นเอเจนต์จาก CLI (คู่มือปี 2026)</title>
      <dc:creator>Thanawat Wongchai</dc:creator>
      <pubDate>Wed, 20 May 2026 08:45:04 +0000</pubDate>
      <link>https://forem.com/thanawat_wonchai/withiildkhaaaichcchaayothekhneecchntcchaak-cli-khuumuuepii-2026-3fp9</link>
      <guid>https://forem.com/thanawat_wonchai/withiildkhaaaichcchaayothekhneecchntcchaak-cli-khuumuuepii-2026-3fp9</guid>
      <description>&lt;p&gt;เอเจนต์เขียนโค้ด CLI อย่าง Claude Code หรือ Codex ช่วยให้ทำงานเร็วขึ้น แต่ค่าโทเค็นจะพุ่งทันทีถ้าปล่อยให้มันอ่าน repo ทั้งก้อน รัน test ซ้ำหลายรอบ และส่งประวัติสนทนาทั้งหมดกลับเข้าโมเดลทุกเทิร์น ข่าวดีคือคุณลดค่าใช้จ่ายได้จากบรรทัดคำสั่ง: จำกัดบริบท, ทำ output ให้สั้น, ใช้ prompt caching, route งานง่ายไปโมเดลราคาถูก และวัดต้นทุนต่อการรันจริง&lt;/p&gt;

&lt;p&gt;&lt;a href="https://apidog.com/?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation" class="crayons-btn crayons-btn--primary"&gt;ลองใช้ Apidog วันนี้&lt;/a&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  สรุปสั้นๆ (TL;DR)
&lt;/h2&gt;

&lt;p&gt;ถ้าต้องการลดค่าใช้จ่ายโทเค็นของ CLI coding agents ให้เริ่มจากสิ่งเหล่านี้:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;จำกัด scope ก่อนให้เอเจนต์ทำงาน&lt;/li&gt;
&lt;li&gt;ทำ &lt;code&gt;CLAUDE.md&lt;/code&gt; หรือ memory file ให้สั้น&lt;/li&gt;
&lt;li&gt;ใช้ &lt;code&gt;/compact&lt;/code&gt; หรือ &lt;code&gt;/clear&lt;/code&gt; เมื่อเปลี่ยนงาน&lt;/li&gt;
&lt;li&gt;เปิด prompt caching สำหรับ prefix ที่เสถียร&lt;/li&gt;
&lt;li&gt;ใช้โมเดลราคาถูกกับงานย่อยที่ความเสี่ยงต่ำ&lt;/li&gt;
&lt;li&gt;ลด output จาก test runner, install command, logs และ diff&lt;/li&gt;
&lt;li&gt;วัด token usage และต้นทุนต่อ run&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;เป้าหมายคือส่งเฉพาะบริบทที่จำเป็นให้โมเดล ไม่ใช่ส่งทั้ง repo และประวัติทั้งหมดทุกครั้ง&lt;/p&gt;

&lt;h2&gt;
  
  
  ทำไม CLI agents ถึงกินโทเค็นเยอะ
&lt;/h2&gt;

&lt;p&gt;ปัญหาหลักไม่ได้อยู่ที่โมเดลอย่างเดียว แต่อยู่ที่พฤติกรรม default ของเอเจนต์:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;อ่านไฟล์ทั้งไฟล์ ทั้งที่ต้องใช้แค่ฟังก์ชันเดียว&lt;/li&gt;
&lt;li&gt;ส่ง system prompt, tool definitions และ repo context ซ้ำทุกเทิร์น&lt;/li&gt;
&lt;li&gt;เล่นซ้ำ conversation history ทั้งหมด&lt;/li&gt;
&lt;li&gt;dump log จาก test runner หรือ command line กลับเข้า context&lt;/li&gt;
&lt;li&gt;ใช้โมเดลแพงกับงานง่าย เช่น commit message หรือ changelog&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ตัวอย่าง: งาน refactor ที่ต้องใช้โค้ดจริงประมาณ 2,000 tokens อาจกลายเป็น request ขนาด 180,000 tokens ได้ ถ้าเอเจนต์อ่านหลายไฟล์ รัน test verbose และแบก history ยาวๆ ไปด้วย&lt;/p&gt;

&lt;p&gt;ค่าใช้จ่ายที่ซ่อนอีกจุดคือการ debug API เอเจนต์ที่เรียก API ภายในซึ่งไม่เสถียรจะ retry, อ่าน error, อ่าน docs ซ้ำ และวนหลายรอบ ทุก loop มีค่าโทเค็นเต็ม&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 หากเอเจนต์ของคุณต้องทำงานกับ API ให้ design, mock และ test API เหล่านั้นใน Apidog ก่อน แล้วค่อยให้เอเจนต์เขียนโค้ดกับ contract ที่คาดเดาได้ วิธีนี้ช่วยลดการลองผิดลองถูกกับ endpoint จริงที่อาจสร้าง error และกินโทเค็นโดยไม่จำเป็น&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  โทเค็นหายไปไหนในการรันจริง
&lt;/h2&gt;

&lt;p&gt;หนึ่ง turn ของเอเจนต์มีทั้ง input tokens และ output tokens คุณจ่ายทั้งสองฝั่ง โดย output tokens มักแพงกว่า input tokens หลายเท่า&lt;/p&gt;

&lt;p&gt;สิ่งที่อยู่ใน input payload มักประกอบด้วย:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;System prompt และ tool definitions&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
เช่น instruction ของ agent และ JSON schema ของ tools มักถูกส่งซ้ำทุก turn&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Memory/project files&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
เช่น &lt;code&gt;CLAUDE.md&lt;/code&gt;, coding conventions, repo rules&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Conversation history&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
user message, model response, tool call และ tool output เก่าทั้งหมด&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;ไฟล์ที่เอเจนต์อ่าน&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
การอ่านไฟล์ 1,200 บรรทัดครั้งเดียวอาจมีขนาด 12,000–18,000 tokens&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Tool output&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
log จาก &lt;code&gt;npm install&lt;/code&gt;, test failure, stack trace, &lt;code&gt;git diff&lt;/code&gt;, lockfile diff&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;จุดสำคัญคือ conversation history ถูกส่งซ้ำทุก turn ดังนั้น session 30 turns ไม่ได้แพงแค่ 30 เท่าของ 1 turn แต่แพงขึ้นตาม prefix ที่โตขึ้นเรื่อยๆ&lt;/p&gt;

&lt;p&gt;ถ้าต้องการเข้าใจเรื่อง session/window เพิ่มเติม อ่านได้ที่ &lt;a href="http://apidog.com/blog/claude-code-token-window-reset?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;วิธีการรีเซ็ตหน้าต่างโทเค็นของ Claude Code&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  1. จำกัด scope ก่อนให้เอเจนต์เริ่มงาน
&lt;/h2&gt;

&lt;p&gt;โทเค็นที่ถูกที่สุดคือโทเค็นที่ไม่ต้องส่ง อย่าเริ่มจาก prompt กว้างๆ เช่น:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude &lt;span class="s2"&gt;"refactor the billing logic"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ให้ระบุไฟล์และขอบเขตให้ชัด:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude &lt;span class="s2"&gt;"refactor the retry logic so it uses exponential backoff,
only in src/payments/retry.ts and src/payments/retry.test.ts"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ถ้าต้องให้เอเจนต์สำรวจ codebase ให้จำกัด directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude &lt;span class="s2"&gt;"find the payment retry implementation under src/payments only,
then propose the minimal change"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;แนวทางใช้งาน:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;หนึ่ง prompt ควรมีหนึ่งงานหลัก&lt;/li&gt;
&lt;li&gt;ระบุไฟล์หรือ directory&lt;/li&gt;
&lt;li&gt;บอกสิ่งที่ห้ามแตะ เช่น migration, generated files, lockfiles&lt;/li&gt;
&lt;li&gt;หลีกเลี่ยงคำสั่งประเภท “scan the whole repo”&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2. ทำ memory file ให้สั้น
&lt;/h2&gt;

&lt;p&gt;ไฟล์อย่าง &lt;code&gt;CLAUDE.md&lt;/code&gt; ถูกโหลดเข้า context บ่อยมาก ถ้ามันกลายเป็น wiki ยาว 4,000 tokens ทีมจะจ่ายซ้ำทุก turn&lt;/p&gt;

&lt;p&gt;ตรวจขนาดแบบคร่าวๆ:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; CLAUDE.md | &lt;span class="nb"&gt;awk&lt;/span&gt; &lt;span class="s1"&gt;'{print "≈", int($1/4), "tokens per turn"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ควรเก็บเฉพาะ:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# CLAUDE.md&lt;/span&gt;

&lt;span class="gu"&gt;## Commands&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Run tests: npm test --silent -- --reporter=dot
&lt;span class="p"&gt;-&lt;/span&gt; Typecheck: npm run typecheck
&lt;span class="p"&gt;-&lt;/span&gt; Lint: npm run lint

&lt;span class="gu"&gt;## Rules&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Do not edit generated files.
&lt;span class="p"&gt;-&lt;/span&gt; Do not modify package-lock.json unless dependency changes are requested.
&lt;span class="p"&gt;-&lt;/span&gt; Keep changes minimal and scoped to the requested files.

&lt;span class="gu"&gt;## References&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; API contracts: docs/api/
&lt;span class="p"&gt;-&lt;/span&gt; Architecture notes: docs/architecture.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ไม่ควรใส่:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;onboarding docs ทั้งชุด&lt;/li&gt;
&lt;li&gt;changelog ยาวๆ&lt;/li&gt;
&lt;li&gt;architecture document ทั้งไฟล์&lt;/li&gt;
&lt;li&gt;ตัวอย่างโค้ดจำนวนมากที่ไม่ได้ใช้ทุกงาน&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ถ้าเอกสารบางส่วนใช้เดือนละครั้ง ให้เก็บไว้เป็นไฟล์แยก แล้วให้เอเจนต์อ่านเมื่อจำเป็น&lt;/p&gt;

&lt;h2&gt;
  
  
  3. ใช้ &lt;code&gt;/compact&lt;/code&gt; หรือ &lt;code&gt;/clear&lt;/code&gt; เมื่อเปลี่ยนงาน
&lt;/h2&gt;

&lt;p&gt;session ยาวคือแหล่งกินโทเค็นหลัก เพราะทุก turn ใหม่ต้องแบก history เก่าทั้งหมด&lt;/p&gt;

&lt;p&gt;ใน Claude Code:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;ใช้เมื่อ session ยาว แต่ยังอยากเก็บสรุปของงานเดิมไว้&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;ใช้เมื่อเริ่มงานใหม่ที่ไม่เกี่ยวข้อง&lt;/p&gt;

&lt;p&gt;กฎง่ายๆ:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;หนึ่ง logical task ต่อหนึ่ง session&lt;/li&gt;
&lt;li&gt;หลัง refactor เสร็จแล้ว อย่าใช้ session เดิมไปเขียน docs ต่อ&lt;/li&gt;
&lt;li&gt;ก่อนเริ่มงานใหม่ ให้ &lt;code&gt;/clear&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;ถ้างานยังต่อเนื่องแต่ history ยาว ให้ &lt;code&gt;/compact&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ดู workflow เพิ่มเติมได้ที่ &lt;a href="http://apidog.com/blog/claude-code-workflows?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;เวิร์กโฟลว์ของ Claude Code&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  4. ใช้ ignore files เพื่อตัดไฟล์ที่ไม่ควรเห็น
&lt;/h2&gt;

&lt;p&gt;ให้เอเจนต์หลีกเลี่ยงไฟล์ที่สร้างขึ้นหรือไม่ควรแก้ เช่น:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node_modules/
dist/
build/
coverage/
.next/
.nuxt/
*.log
package-lock.json
pnpm-lock.yaml
yarn.lock
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ถ้าเอเจนต์ไม่เห็น &lt;code&gt;dist/&lt;/code&gt;, &lt;code&gt;coverage/&lt;/code&gt; หรือ lockfile diff มันก็ไม่เสียโทเค็นกับสิ่งเหล่านั้น&lt;/p&gt;

&lt;p&gt;เพิ่มกฎใน memory file ด้วย:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;Do not read or edit generated files, build output, coverage output, or dependency directories.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  5. เปิด prompt caching สำหรับ prefix ที่เสถียร
&lt;/h2&gt;

&lt;p&gt;Prompt caching ช่วยลดค่าใช้จ่ายของ prefix ที่ส่งซ้ำ เช่น system prompt, tools และ repo conventions&lt;/p&gt;

&lt;p&gt;แนวคิดคือ:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;วางข้อมูลที่เสถียรไว้ด้านหน้า&lt;/li&gt;
&lt;li&gt;วาง input ที่เปลี่ยนบ่อยไว้ด้านหลัง&lt;/li&gt;
&lt;li&gt;cache เฉพาะ prefix ที่ไม่เปลี่ยน&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ตัวอย่างถ้าเรียก API เอง:&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="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;claude-sonnet-4-6&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;max_tokens&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2048&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;system&lt;/span&gt;&lt;span class="o"&gt;=&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;type&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;text&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;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;SYSTEM_PROMPT&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;REPO_CONVENTIONS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cache_control&lt;/span&gt;&lt;span class="sh"&gt;"&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;type&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;ephemeral&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&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;role&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;user&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;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;user_task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;u&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;usage&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cache write:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cache_creation_input_tokens&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cache read :&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cache_read_input_tokens&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fresh input:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;input_tokens&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ข้อควรระวัง:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;prefix ต้อง byte-stable&lt;/li&gt;
&lt;li&gt;อย่าใส่ timestamp หรือข้อมูล runtime ไว้ก่อน cache boundary&lt;/li&gt;
&lt;li&gt;ถ้าเปลี่ยน character เดียวก่อนจุด cache อาจทำให้ cache miss&lt;/li&gt;
&lt;li&gt;จัดกลุ่มงานที่เกี่ยวข้องให้รันใกล้กัน เพื่อใช้ cache ที่ยัง warm อยู่&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Prompt caching เหมาะมากกับ agent ที่ใช้ system prompt และ repo rules เดิมซ้ำหลายสิบครั้งต่อวัน&lt;/p&gt;

&lt;p&gt;ถ้าใช้ Codex หรือ OpenAI models ที่มี cached input discount หลักการคล้ายกัน แม้รายละเอียด implementation ต่างกัน อ่านเสริมได้ที่ &lt;a href="http://apidog.com/blog/how-to-use-gpt-5-5-free-codex?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;การรัน GPT-5.5 ฟรีผ่าน Codex&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Route งานง่ายไปโมเดลราคาถูก
&lt;/h2&gt;

&lt;p&gt;ไม่ใช่ทุกงานต้องใช้โมเดลหลัก งานเหล่านี้มักใช้โมเดลเล็กได้:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;commit message&lt;/li&gt;
&lt;li&gt;changelog&lt;/li&gt;
&lt;li&gt;summarize diff&lt;/li&gt;
&lt;li&gt;generate boilerplate test&lt;/li&gt;
&lt;li&gt;explain lint error&lt;/li&gt;
&lt;li&gt;rename variable แบบตรงไปตรงมา&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ตัวอย่าง:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# งานง่าย ใช้โมเดลถูก&lt;/span&gt;
claude &lt;span class="nt"&gt;--model&lt;/span&gt; haiku &lt;span class="s2"&gt;"write a conventional commit message for the staged diff"&lt;/span&gt;

&lt;span class="c"&gt;# งานยาก ใช้โมเดลแรง&lt;/span&gt;
claude &lt;span class="nt"&gt;--model&lt;/span&gt; sonnet &lt;span class="s2"&gt;"redesign the caching layer for the payments service"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;แนวทางที่ดีคือ default เป็นโมเดลราคาถูก แล้วค่อยยกระดับเมื่อจำเป็น แทนที่จะใช้โมเดลแพงกับทุกอย่าง&lt;/p&gt;

&lt;p&gt;ถ้า framework รองรับ sub-agent ให้ใช้โมเดลเล็กกับงานค้นหา/สรุป แล้วส่งผลลัพธ์สั้นๆ กลับให้ parent agent ที่ใช้โมเดลแพง&lt;/p&gt;

&lt;p&gt;อ่านรูปแบบ autonomous loop เพิ่มเติมได้ที่ &lt;a href="http://apidog.com/blog/goal-command-codex-claude-code-autonomous-agents?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;คำสั่ง goal ใน Codex และ Claude Code&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;การ route ไม่ได้ช่วยแค่ค่าเงิน แต่ยังช่วยยืด quota ในแผนที่มี usage limit ด้วย แม้จะมี &lt;a href="http://apidog.com/blog/claude-code-weekly-limits-50-percent-increase-july-2026?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;การเพิ่มขีดจำกัดรายสัปดาห์ของ Claude Code&lt;/a&gt; การใช้โมเดลแพงกับงานเล็กก็ยังเป็นการเผา quota โดยไม่จำเป็น&lt;/p&gt;

&lt;h2&gt;
  
  
  7. ทำ command output ให้สั้น
&lt;/h2&gt;

&lt;p&gt;Tool output เป็นตัวกินงบแบบเงียบๆ เพราะทุกบรรทัดที่ command print ออกมาอาจถูกส่งกลับเข้า context&lt;/p&gt;

&lt;p&gt;เปลี่ยนจาก command ที่ verbose:&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เป็นแบบสั้น:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;--silent&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nt"&gt;--reporter&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;dot
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ติดตั้ง dependency แบบลด noise:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--silent&lt;/span&gt; &lt;span class="nt"&gt;--no-audit&lt;/span&gt; &lt;span class="nt"&gt;--no-fund&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;จำกัด test output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pytest &lt;span class="nt"&gt;-q&lt;/span&gt; 2&amp;gt;&amp;amp;1 | &lt;span class="nb"&gt;tail&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; 30
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ดู diff แบบสรุปก่อน:&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;กรองเฉพาะ error:&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;2&amp;gt;&amp;amp;1 | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s2"&gt;"(FAIL|✗|Error)"&lt;/span&gt; | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; 20
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ถ้าเอเจนต์ต้อง debug test failure มันมักต้องการแค่:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;test ไหน fail&lt;/li&gt;
&lt;li&gt;error message&lt;/li&gt;
&lt;li&gt;stack trace ส่วนบน&lt;/li&gt;
&lt;li&gt;expected vs actual&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ไม่ต้องการ log ทั้งหมด 5,000 บรรทัด&lt;/p&gt;

&lt;h2&gt;
  
  
  8. ให้เอเจนต์อ่านเฉพาะส่วนที่เกี่ยวข้อง
&lt;/h2&gt;

&lt;p&gt;แทนที่จะให้เอเจนต์อ่านไฟล์ 1,500 บรรทัด ให้สั่งให้ค้นหา symbol ก่อน:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude &lt;span class="s2"&gt;"find the function that handles payment retry,
read only that function and nearby tests, then suggest the minimal patch"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;หรือใช้ shell ช่วยตัดบริบท:&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;-n&lt;/span&gt; &lt;span class="s2"&gt;"function retryPayment"&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; src/payments/retry.ts
&lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s1"&gt;'120,220p'&lt;/span&gt; src/payments/retry.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ถ้าใช้ ripgrep:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rg &lt;span class="s2"&gt;"retryPayment|exponentialBackoff|RetryPolicy"&lt;/span&gt; src/payments
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เป้าหมายคือให้โมเดลเห็น context ขนาด 500–1,000 tokens แทนที่จะเป็นทั้งไฟล์ขนาด 18,000 tokens&lt;/p&gt;

&lt;h2&gt;
  
  
  9. จำกัด retrieval/RAG
&lt;/h2&gt;

&lt;p&gt;ถ้า agent ใช้ code search หรือ RAG บนเอกสาร ให้จำกัดจำนวน chunk และขนาด chunk&lt;/p&gt;

&lt;p&gt;ตัวอย่าง configuration ที่ควรตั้ง:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"retrieval"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"max_chunks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"chunk_size_tokens"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"include_full_file"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;หลักการ:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;chunk สั้นแต่ตรงคำถามดีกว่า chunk ยาวจำนวนมาก&lt;/li&gt;
&lt;li&gt;อย่าดึง full file ถ้าไม่จำเป็น&lt;/li&gt;
&lt;li&gt;ให้ ranking เลือกเฉพาะ context ที่เกี่ยวข้องจริง&lt;/li&gt;
&lt;li&gt;log จำนวน retrieved tokens เพื่อวัดผล&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;คุณจ่ายสำหรับทุก token ที่ดึงมา แม้โมเดลจะไม่ได้ใช้มันตอบก็ตาม&lt;/p&gt;

&lt;h2&gt;
  
  
  10. วัดต้นทุนต่อการรัน
&lt;/h2&gt;

&lt;p&gt;อย่าดูแค่ bill รายเดือน ให้เก็บต้นทุนต่อ task เช่น:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;daily refactor run&lt;/li&gt;
&lt;li&gt;PR review run&lt;/li&gt;
&lt;li&gt;test-fix run&lt;/li&gt;
&lt;li&gt;API integration run&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ถ้าเรียก API เอง ให้เก็บ usage:&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="n"&gt;u&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;usage&lt;/span&gt;

&lt;span class="n"&gt;INPUT_RATE&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;3.00&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1_000_000&lt;/span&gt;
&lt;span class="n"&gt;OUTPUT_RATE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;15.00&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1_000_000&lt;/span&gt;
&lt;span class="n"&gt;CACHE_READ&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.30&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1_000_000&lt;/span&gt;
&lt;span class="n"&gt;CACHE_WRITE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;3.75&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1_000_000&lt;/span&gt;

&lt;span class="n"&gt;cost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;input_tokens&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;INPUT_RATE&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
    &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output_tokens&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;OUTPUT_RATE&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
    &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cache_read_input_tokens&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;CACHE_READ&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
    &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cache_creation_input_tokens&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;CACHE_WRITE&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="s"&gt;run cost ≈ $&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;cost&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;(in=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;input_tokens&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; out=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output_tokens&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cache_read=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cache_read_input_tokens&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ถ้าใช้ CLI ให้ใช้วิธีเหล่านี้:&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;# ตรวจ cost ของ session&lt;/span&gt;
claude /cost
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;หรือแยก API key ตาม project/agent เพื่อดู usage จาก provider console&lt;/p&gt;

&lt;p&gt;หรือห่อ command ด้วย script ที่ log ข้อมูลลง CSV:&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="nv"&gt;TASK&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;START&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;-Iseconds&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

claude &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TASK&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="nv"&gt;END&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;-Iseconds&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$START&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;$END&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;$TASK&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; agent-runs.csv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;จากนั้นเทียบต้นทุนก่อน/หลังปรับ:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ก่อนใช้ prompt caching&lt;/li&gt;
&lt;li&gt;หลังลด &lt;code&gt;CLAUDE.md&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;หลังเปลี่ยน test reporter&lt;/li&gt;
&lt;li&gt;หลัง route งานง่ายไปโมเดลถูก&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ถ้าตัวเลขไม่ลด แปลว่ากลยุทธ์นั้นอาจไม่ใช่จุดรั่วหลักของคุณ&lt;/p&gt;

&lt;h2&gt;
  
  
  ตารางเปรียบเทียบกลยุทธ์
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;กลยุทธ์&lt;/th&gt;
&lt;th&gt;การประหยัดโทเค็นโดยทั่วไป&lt;/th&gt;
&lt;th&gt;ความพยายาม&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;จำกัดขอบเขตการทำงาน เช่น ระบุชื่อไฟล์&lt;/td&gt;
&lt;td&gt;30–60% ของ input ต่อ run&lt;/td&gt;
&lt;td&gt;ต่ำ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ทำ memory file ให้สั้นและเสถียร&lt;/td&gt;
&lt;td&gt;5–15% ต่อ turn&lt;/td&gt;
&lt;td&gt;ต่ำ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ใช้ &lt;code&gt;/compact&lt;/code&gt; หรือ &lt;code&gt;/clear&lt;/code&gt; ระหว่างงาน&lt;/td&gt;
&lt;td&gt;40–80% สำหรับ session ยาว&lt;/td&gt;
&lt;td&gt;ต่ำ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Prompt caching สำหรับ prefix ที่เสถียร&lt;/td&gt;
&lt;td&gt;ประมาณ 90% สำหรับส่วนที่ cache&lt;/td&gt;
&lt;td&gt;ปานกลาง&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Route งานง่ายไปโมเดลราคาถูก&lt;/td&gt;
&lt;td&gt;50–80% สำหรับงานย่อยนั้น&lt;/td&gt;
&lt;td&gt;ปานกลาง&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ลด/กรอง tool output&lt;/td&gt;
&lt;td&gt;20–50% สำหรับ run ที่ใช้ tools เยอะ&lt;/td&gt;
&lt;td&gt;ต่ำ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;อ่านเฉพาะส่วนของไฟล์&lt;/td&gt;
&lt;td&gt;70–95% สำหรับไฟล์ใหญ่&lt;/td&gt;
&lt;td&gt;ต่ำ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;จำกัด retrieval/RAG&lt;/td&gt;
&lt;td&gt;30–60% สำหรับ agent ที่ใช้ retrieval มาก&lt;/td&gt;
&lt;td&gt;ปานกลาง&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;วัดต้นทุนต่อ run&lt;/td&gt;
&lt;td&gt;ไม่ลดโดยตรง แต่ทำให้ optimize ได้จริง&lt;/td&gt;
&lt;td&gt;ต่ำ&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;ตัวเลขเป็นช่วงโดยประมาณ ผลจริงขึ้นอยู่กับ workflow และความสิ้นเปลืองตั้งต้นของแต่ละทีม&lt;/p&gt;

&lt;h2&gt;
  
  
  Checklist สำหรับนำไปใช้ทันที
&lt;/h2&gt;

&lt;p&gt;เริ่มจากรายการที่ทำครั้งเดียวแล้วได้ผลทุก run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;[ ] ลด CLAUDE.md ให้เหลือเฉพาะ command, rule และ pointer
[ ] เพิ่ม ignore สำหรับ generated files, build output, coverage, dependencies
[ ] เปลี่ยน test command ให้ silent/summary
[ ] ใช้ git diff --stat ก่อน full diff
[ ] สั่ง agent ให้อ่านเฉพาะ function หรือไฟล์ที่ระบุ
[ ] ใช้ /compact เมื่อ session ยาว
[ ] ใช้ /clear เมื่อเปลี่ยนงาน
[ ] ตั้งโมเดลราคาถูกเป็น default สำหรับงานง่าย
[ ] เปิด prompt caching ถ้าเรียก model API เอง
[ ] log token usage หรือต้นทุนต่อ task
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  บทสรุป
&lt;/h2&gt;

&lt;p&gt;ค่าโทเค็นของ CLI coding agents ลดได้โดยไม่ต้องเปลี่ยนคุณภาพของงาน จุดที่ควรจัดการคือบริบทที่ส่งซ้ำ, output ที่ไม่จำเป็น และการใช้โมเดลแพงกับงานที่ไม่ต้องใช้ reasoning สูง&lt;/p&gt;

&lt;p&gt;เริ่มจากสิ่งที่ง่ายที่สุด: scope งานให้แคบ, ทำ command output ให้เงียบ, ลด memory file และ clear session ระหว่างงาน จากนั้นค่อยเพิ่ม prompt caching, model routing และ cost tracking เพื่อให้การประหยัดวัดผลได้จริง&lt;/p&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>cli</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Google I/O 2026 Dev Keynote: Recap</title>
      <dc:creator>Khairunnisaas</dc:creator>
      <pubDate>Wed, 20 May 2026 08:43:17 +0000</pubDate>
      <link>https://forem.com/khairunnisaas/google-io-2026-dev-keynote-recap-4afi</link>
      <guid>https://forem.com/khairunnisaas/google-io-2026-dev-keynote-recap-4afi</guid>
      <description>&lt;p&gt;In case you missed it, here's a recap of what Google announced at I/O today. Some of these are updates, some are brand new. Let's get into it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Antigravity Ecosystem
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Antigravity 2.0&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Google officially introduced Antigravity 2.0, the next evolution of its AI development platform.&lt;/p&gt;

&lt;p&gt;Think of it as a mission control center for AI agents. Instead of just chatting with an AI assistant, Antigravity lets developers orchestrate multiple agents, tools, workflows, and cloud resources in one place. It’s designed for teams and enterprises that want to build agent-powered applications at scale.&lt;/p&gt;

&lt;p&gt;For enterprise users, Antigravity connects directly to your Google Cloud project and automatically follows the same security rules, permissions, and policies your organization already uses.&lt;/p&gt;

&lt;p&gt;Google is basically trying to turn AI agents into actual coworkers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Antigravity IDE&lt;/strong&gt;&lt;br&gt;
Because Antigravity is now an agentic platform, Google needed a separate place for the code editor experience. That's the Antigravity IDE. It's basically what the original Antigravity app was.&lt;/p&gt;

&lt;p&gt;Honestly, I'm not sure why Google didn't just make two modes in one app. But okay.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Antigravity CLI&lt;/strong&gt;&lt;br&gt;
From what Google showed during the keynote, this looks like a revamped replacement for Gemini CLI.&lt;/p&gt;

&lt;p&gt;Google didn’t fully explain the differences on stage, but the biggest clue is this:&lt;/p&gt;

&lt;p&gt;Google already published a migration guide for moving from Gemini CLI to Antigravity CLI, which strongly suggests Gemini CLI will eventually be deprecated.&lt;/p&gt;

&lt;p&gt;If you want to read more about the transition, Google posted the official update here: &lt;a href="https://developers.googleblog.com/an-important-update-transitioning-gemini-cli-to-antigravity-cli/?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;Google’s migration update for Antigravity CLI&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I also don't know why they make a new product for this. I mean, why not just updating the Gemini CLI?&lt;/p&gt;

&lt;h2&gt;
  
  
  Android Development Is Getting More Agentic Too
&lt;/h2&gt;

&lt;p&gt;Google also announced several updates focused on Android development.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Android CLI + Android Knowledge Base&lt;/strong&gt;&lt;br&gt;
Google officially brought Android support into Antigravity through Android CLI — a tool that prepares agents for Android development workflows.&lt;/p&gt;

&lt;p&gt;One of its biggest features is the &lt;strong&gt;Android Knowledge Base&lt;/strong&gt;, which acts as a constantly updated source of official Android developer guidance. This allows AI agents to pull the latest best practices, APIs, and documentation while working on your project.&lt;/p&gt;

&lt;p&gt;Google also introduced something called &lt;strong&gt;Android Skills&lt;/strong&gt; — open-source skills that help LLMs better understand Android codebases and execute more complex workflows correctly.&lt;/p&gt;

&lt;p&gt;Google's internal team claims this uses 70% fewer tokens and completes tasks 3x faster. Of course, those are Google’s own benchmarks, so we’ll have to wait for real-world testing to see how accurate those numbers are.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Migration Agent — Possibly One of the Coolest Demos&lt;/strong&gt;&lt;br&gt;
Google gave a preview of Migration Agent — a tool that can migrate your existing app into a native Kotlin Android app. React Native, web framework, or iOS — it doesn't matter. Still in preview, but the concept is interesting.&lt;/p&gt;

&lt;h2&gt;
  
  
  Web Updates
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Modern Web Guidance&lt;/strong&gt;&lt;br&gt;
Moving over to web development, Google introduced something called &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Modern Web Guidance.&lt;/strong&gt;&lt;br&gt;
This is basically a collection of AI-ready web development best practices and tooling guidance designed specifically for AI agents.&lt;/p&gt;

&lt;p&gt;The goal is simple:&lt;/p&gt;

&lt;p&gt;Google wants AI coding agents to stop generating outdated web code.&lt;/p&gt;

&lt;p&gt;Modern Web Guidance integrates directly with Baseline so agents can understand which web platform features are actually safe and modern to use across browsers.&lt;/p&gt;

&lt;p&gt;This is a pretty big deal because one of the biggest problems with AI-generated frontend code right now is that it often recommends outdated APIs or old patterns.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;WebMCP&lt;/strong&gt;&lt;br&gt;
During the Modern Web Guidance demo, Google also introduced &lt;strong&gt;WebMCP&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So… what exactly is it?&lt;/p&gt;

&lt;p&gt;According to Google’s developer docs:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“MCP is a proposed web standard to help you build and expose structured tools for AI agents.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In simpler terms:&lt;/p&gt;

&lt;p&gt;WebMCP lets websites explain to AI agents how they should interact with them.&lt;/p&gt;

&lt;p&gt;Imagine visiting a complicated dashboard or settings page and instead of manually configuring everything yourself, you could simply tell Gemini:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Set this up for me.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And the AI would understand how to navigate and interact with the site properly.&lt;/p&gt;

&lt;p&gt;That’s basically the future Google is aiming for.&lt;/p&gt;

&lt;p&gt;WebMCP is still experimental for now, and Google announced that the experimental MCP APIs will begin trials in Chrome 149.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HTML-in-Canvas API&lt;/strong&gt;&lt;br&gt;
Last but definitely not least, Google announced the new HTML-in-Canvas API.&lt;/p&gt;

&lt;p&gt;This API allows developers to place real DOM elements directly inside a canvas.&lt;/p&gt;

&lt;p&gt;That might sound small, but it actually solves one of the biggest limitations of canvas-based apps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;accessibility and interactivity.&lt;/li&gt;
&lt;li&gt;Because the elements are real DOM nodes:&lt;/li&gt;
&lt;li&gt;They’re searchable&lt;/li&gt;
&lt;li&gt;Accessible&lt;/li&gt;
&lt;li&gt;Selectable&lt;/li&gt;
&lt;li&gt;Compatible with browser features&lt;/li&gt;
&lt;li&gt;Better for SEO&lt;/li&gt;
&lt;li&gt;Easier to interact with&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This could become huge for browser games, design tools, editors, and highly interactive web apps.&lt;/p&gt;

&lt;p&gt;That's everything from the developer keynote. The general direction is clear — Google is going all-in on agents. Antigravity is the center of that story.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>googleio</category>
      <category>antigravity</category>
    </item>
    <item>
      <title>Quantitative Content Methodology: 5-Layer Content Framework</title>
      <dc:creator>Gülşah Arslan</dc:creator>
      <pubDate>Wed, 20 May 2026 08:43:09 +0000</pubDate>
      <link>https://forem.com/gulsaharslan/quantitative-content-methodology-5-layer-content-framework-3bad</link>
      <guid>https://forem.com/gulsaharslan/quantitative-content-methodology-5-layer-content-framework-3bad</guid>
      <description>&lt;p&gt;Quantitative Content Methodology (QCM) treats content not as mere text, but as a mathematical dataset optimized for search engines and LLMs. In this guide, we explain the 5-layer content framework applicable to any topic, step-by-step.&lt;/p&gt;

&lt;p&gt;Key Takeaways&lt;br&gt;
• QCM builds pages based on semantic vectors, information density, and probabilistic word distribution.&lt;br&gt;
• An entity pool is extracted prior to production; content is fed from this pool rather than through random word selection.&lt;br&gt;
• An information density budget is defined for each section—targeting at least 2.5 verifiable data points per 100 words.&lt;br&gt;
• The first sentence under every H2 heading serves as an "atomic answer"; it remains meaningful even when extracted from context by an LLM.&lt;br&gt;
• JSON-LD schemas (FAQPage, HowTo, Dataset) present content to search engines as variable-value pairs.&lt;/p&gt;

&lt;p&gt;Ranking on the first page is no longer enough. Generative search engines like Google’s AI Overviews, ChatGPT, and Gemini exclusively cite structured, high-information-density pages as sources when generating direct answers to user queries. QCM is an content production framework designed for this new reality.&lt;/p&gt;

&lt;p&gt;The 5 layers below represent the methodological steps to be applied at every stage of the production process. We will use "Core Web Vitals Optimization for E-commerce Sites" as our example topic, though the skeleton is adaptable to any industry.&lt;/p&gt;

&lt;p&gt;**The 5 Layers of QCM&lt;br&gt;
**Each layer builds upon the previous one. Skipping steps diminishes the effectiveness of subsequent stages.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Semantic Vector Map
&lt;/h2&gt;

&lt;p&gt;Before writing, the main entity (core concept) and sub-entities with vectorial proximity are identified. Embedding models (BERT, Sentence-BERT) measure word proximity using cosine similarity. If the content is written while maintaining this cluster distribution, the page signals that it "covers the entire topic."&lt;br&gt;
Layer   Entity  Proximity   Target Frequency&lt;br&gt;
Core    Core Web Vitals 1.00    8–12&lt;br&gt;
Primary LCP, INP, CLS   0.85–0.92 4–6&lt;br&gt;
Secondary   TBT, TTFB, FCP  0.70–0.80 2–3&lt;br&gt;
Contextual  e-commerce, conversion, cart    0.55–0.65 1–2&lt;br&gt;
Authority   PageSpeed, Lighthouse, web.dev  0.50–0.60 1–2&lt;br&gt;
Recommendation: Define at least 15 entities for a topic. Fewer leads to superficial content; more leads to topic dilution.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Information Density Budget
&lt;/h2&gt;

&lt;p&gt;The minimum concrete information unit—a figure, threshold, procedure, or definition—required per 100 words is pre-calculated per section. This approach prevents the "empty paragraph" syndrome and increases the Information Gain ratio.&lt;br&gt;
• Target Information Gain: At least 1.3x higher than the average of the top 10 competing pages. That is, 30% more verifiable data per 100 words than the competition.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Probabilistic Word Distribution
&lt;/h2&gt;

&lt;p&gt;The frequency and placement of key terms are pre-determined. A mathematical balance is established between over-repetition (keyword stuffing) and under-repetition (semantic weakness) based on TF-IDF and BM25 targets.&lt;br&gt;
Important Positioning Rules:&lt;br&gt;
• The core term must appear in the H1, H2, and both the first and last 100 words.&lt;br&gt;
• Primary terms must be positioned in at least one H2 heading.&lt;br&gt;
• Contextual terms should appear 1–2 times within the natural flow without feeling forced.&lt;br&gt;
• Natural readability always takes precedence over frequency targets. These targets are ceilings, not mandates.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Structural Skeleton (LLM-friendly layout)
&lt;/h2&gt;

&lt;p&gt;To enable LLMs and AI Overviews to cite content directly, each section is structured as a question-answer atom. The answer is completed in the first sentence; justifications follow in subsequent sentences.&lt;br&gt;
• Atomic Answer Rule: The first sentence under each H2 contains the independently readable answer to the query. Even if an LLM extracts that sentence alone, the information remains accurate and complete.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. JSON-LD Schema Layer
&lt;/h2&gt;

&lt;p&gt;This structure explicitly notifies Google and LLMs of the page’s mathematical clarity. JSON-LD schemas present information as variable-value pairs. Google bots no longer ask "what is this about?"; they reach the clarity of "The answer to Question A is B."&lt;br&gt;
Key Schemas used in QCM:&lt;br&gt;
• Article: Author, date, publisher info (Mandatory for E-E-A-T signals).&lt;br&gt;
• FAQPage: Each question-answer atom in the FAQ section (Direct candidate for AI Overviews).&lt;br&gt;
• HowTo: For sequential procedures (e.g., LCP reduction steps).&lt;br&gt;
• Dataset: Structured markup for numerical thresholds and tables.&lt;br&gt;
• BreadcrumbList: Page position in site architecture (Critical for topic clusters).&lt;br&gt;
Pre- and Post-Production Audit&lt;br&gt;
Before writing, the following must be answered numerically:&lt;br&gt;
• Has the entity pool been extracted? (Min. 15 entities)&lt;br&gt;
• Is the information density goal set for each section?&lt;br&gt;
• Has the average data point count of the top 10 competitors been measured?&lt;br&gt;
• Is the target Information Gain ratio defined? (1.3x recommended)&lt;br&gt;
Post-publication verification metrics:&lt;br&gt;
• Semantic Coverage: ≥ 85% (via InLinks / Surfer SEO)&lt;br&gt;
• Information Density: ≥ 2.5 (verifiable data / 100w)&lt;br&gt;
• Schema Accuracy: 0 errors (via Rich Results Test)&lt;br&gt;
• LLM Source Test: Top 3 source verification (via ChatGPT / Gemini)&lt;br&gt;
To apply this methodology to your own site and produce content that is shaped by data and speaks to AI, feel free to get in touch.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>data</category>
      <category>llm</category>
      <category>writing</category>
    </item>
  </channel>
</rss>
