<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Andrea Liliana Griffiths</title>
    <description>The latest articles on DEV Community by Andrea Liliana Griffiths (@andreagriffiths11).</description>
    <link>https://dev.to/andreagriffiths11</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F244800%2Fcc8eddc0-f6ec-4ed0-85c9-9dd91204bc57.jpg</url>
      <title>DEV Community: Andrea Liliana Griffiths</title>
      <link>https://dev.to/andreagriffiths11</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/andreagriffiths11"/>
    <language>en</language>
    <item>
      <title>An agent loop that stops itself</title>
      <dc:creator>Andrea Liliana Griffiths</dc:creator>
      <pubDate>Wed, 24 Jun 2026 10:28:20 +0000</pubDate>
      <link>https://dev.to/andreagriffiths11/an-agent-loop-that-stops-itself-cb0</link>
      <guid>https://dev.to/andreagriffiths11/an-agent-loop-that-stops-itself-cb0</guid>
      <description>&lt;p&gt;· &lt;a href="https://dev.to/articles/zh/agent-loop-that-stops-itself/"&gt;阅读中文版 →&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Can you trust what AI writes? And what does it cost to find out? Those are the two honest questions about AI coding, and everyone's loud about both. What I haven't heard much of is that they're the same question. You solve them with one design.&lt;/p&gt;

&lt;p&gt;The bias case is the &lt;a href="https://dl.acm.org/doi/10.1145/3442188.3445922" rel="noopener noreferrer"&gt;familiar one&lt;/a&gt;. A model is trained on a skewed slice of the world, the output inherits the skew, and you can't fully trust it. All true. None of it means you stop, though. It means you stop leaning on one model alone. Run a few, let them check each other, and the thing one model is blind to is usually something another one catches.&lt;/p&gt;

&lt;p&gt;And that fix is exactly what makes cost the second question. Two models cost more than one. Three agents talking to each other cost more than three working alone, and a loop nobody is watching costs whatever it feels like. So you're solving two problems with one design: get enough disagreement to catch the errors, and stop that disagreement from running up a bill you never agreed to. Building the verification and capping it turn out to be the same job.&lt;/p&gt;

&lt;p&gt;Three tools do this at different scales, including one I built myself.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://github.com/samirpatil2000/skills/blob/main/opencode-fusion/SKILL.md" rel="noopener noreferrer"&gt;opencode-fusion&lt;/a&gt;: a panel that argues, then a judge
&lt;/h2&gt;

&lt;p&gt;opencode-fusion is Samir Patil's (&lt;a href="https://x.com/sampatil1010" rel="noopener noreferrer"&gt;@sampatil1010&lt;/a&gt;) local take on OpenRouter's Fusion (&lt;a href="https://x.com/OpenRouter" rel="noopener noreferrer"&gt;@OpenRouter&lt;/a&gt;): run one task across a panel of models at once, then resolve their disagreement instead of averaging it away. The default panel is Sonnet, GPT, and GLM, defined as a bash array you edit to add or drop models. They run in parallel through the OpenCode CLI, each output written to its own temp file. Failures get noted but don't abort the run.&lt;/p&gt;

&lt;p&gt;Then a judge model reads all the outputs and writes a structured report: where the models agree, where they contradict each other and which side is likely right, what every model missed, and what looks risky. A synthesizer takes the original task, the judge's report, and the raw outputs, and produces the single answer you actually see.&lt;/p&gt;

&lt;p&gt;You invoke the whole thing with one line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bash run_fusion.sh &lt;span class="s2"&gt;"&amp;lt;TASK&amp;gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The parallelism is the boring part. What you're actually buying is the disagreement. When two models land on the same answer and a third wanders off somewhere else, that gap tells you something a single confident response never would. The judge does the reading. You get one answer instead of three transcripts.&lt;/p&gt;

&lt;h2&gt;
  
  
  agmsg: agents that message each other
&lt;/h2&gt;

&lt;p&gt;opencode-fusion is one-shot. Ask, the panel answers, done. Sometimes you want the models to go back and forth instead. That's &lt;a href="https://github.com/fujibee/agmsg" rel="noopener noreferrer"&gt;agmsg&lt;/a&gt;, by &lt;a href="https://x.com/fujibee" rel="noopener noreferrer"&gt;@fujibee&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;agmsg lets CLI agents message each other through a shared SQLite file. No daemon, no network, just bash and sqlite3, installed as an agent skill. It's cross-vendor, so Claude Code, Codex, Gemini CLI, and Copilot CLI can join the same team and pass messages. And the messages persist, which is what separates it from the alternatives. A built-in subagent is ephemeral and locked to its parent's vendor. MCP is one agent reaching for tools. agmsg is a different shape: independent agents, different models, talking to each other over a durable channel.&lt;/p&gt;

&lt;p&gt;Install is a one-liner:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bash &amp;lt;&lt;span class="o"&gt;(&lt;/span&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://raw.githubusercontent.com/fujibee/agmsg/main/setup.sh&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After a restart the agents get a command (/agmsg in Claude Code and Copilot CLI, $agmsg in Codex and Gemini CLI), pick a team and a name, and start talking.&lt;/p&gt;

&lt;p&gt;One thing to know before you wire it into anything: agmsg is deliberately dumb. It moves messages and nothing more, so two over-polite agents will happily clarify at each other until your token bill looks like a phone number. Whatever ends that loop has to come from you.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I built
&lt;/h2&gt;

&lt;p&gt;I wired agmsg into a small bridge that watches the shared inbox and delivers messages between three agents automatically. No human relaying anything between them.&lt;/p&gt;

&lt;p&gt;The bridge does one job. It polls the SQLite inbox every four seconds with a SELECT for unread rows, then hands each one to its target agent. No file watcher, nothing clever, just a loop and a query.&lt;/p&gt;

&lt;p&gt;The three agents sit on one team, and none of them run the same way. One runs through a CLI with its model set in a local config file, one runs as a one-shot command, and one answers over an HTTP API. Each is pinned to a different model, and that model lives in the agent's own config, not in the bridge. The bridge doesn't know or care which model is on the other end of a message, and that's the point: I can swap any agent's model without touching the thing that moves the messages.&lt;/p&gt;

&lt;p&gt;The reason for three different models was never that agents can talk to each other. It was that when one of them got something wrong, a model trained on different data was already sitting there to catch it.&lt;/p&gt;

&lt;p&gt;That only holds as far as the models are actually independent. Two trained on mostly the same text share the same blind spots, and when they do they'll agree on a wrong answer as fast as a right one, so the disagreement I'm counting on never shows up. Spanning vendors (gpt-4.1, Sonnet 4.6, and one of my own) buys more independence than three versions of one model would, but it's a hedge, not a guarantee.&lt;/p&gt;

&lt;p&gt;The bridge itself is small, a poll loop and the set of guards below. I'm cleaning it up to open-source it soon.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keeping it from eating itself
&lt;/h2&gt;

&lt;p&gt;agmsg won't stop two agents from clarifying at each other forever. A runaway loop here burns real money, fast, so the containment is all on the bridge. Four guards, each for a different way it goes wrong.&lt;/p&gt;

&lt;p&gt;Two sliding-window counters, both over a 300-second window. One caps total dispatches at 12 per window. The other caps bot-to-bot hops at 6 per window, since that's the exchange that runs away: two agents answering each other with no human around to get bored and stop it. When either limit trips, the message is dropped and logged, never retried. A dropped message is cheaper than a loop.&lt;/p&gt;

&lt;p&gt;Then a per-agent in-flight lock, so each agent handles one turn at a time and can't be stacked with new work while it's still thinking. And wall-clock kills per agent, set to how slow each one is allowed to be: 280 seconds, 150, and 120. A hung turn dies on the clock instead of holding the lock forever.&lt;/p&gt;

&lt;p&gt;Not a token budget. The counters and the clocks bound the cost indirectly, and they're easier to reason about than a dollar figure I'd have to keep recalibrating.&lt;/p&gt;

&lt;h2&gt;
  
  
  /orchestrate: the same idea with a UI
&lt;/h2&gt;

&lt;p&gt;If you don't want to build the plumbing yourself, the &lt;a href="https://gh.io/onlyone" rel="noopener noreferrer"&gt;GitHub Copilot app&lt;/a&gt; does a version of this at a higher level. /orchestrate turns the main session into a coordinator: it spins up child sessions, gives each one its own branch and task, and lets them report back while the main session steers and summarizes. One session, one branch, one PR. Each runs in its own git worktree, so they aren't editing the same files out from under each other, and you pick the model per session.&lt;/p&gt;

&lt;p&gt;Same idea as the bridge, just managed for you: several agents, different models, kept from stepping on each other. You give up the fine control you'd get from building it yourself, and in return you don't have to maintain any of it.&lt;/p&gt;

&lt;p&gt;None of these tools pretend any single model is right. They assume it'll be wrong sometimes, build the check into the workflow, and keep the check cheap.&lt;/p&gt;

&lt;p&gt;That's the whole move. "The model is biased" and "it's too expensive to run" get treated as reasons to wait. They're not. They're two sides of one design problem, and the fix reads the same from either side: run more than one model, let them disagree where they were going to disagree anyway, and put something in the path that reads the disagreement so you don't have to. The cap is what keeps it honest. Reading the disagreement should never cost more than the bug it catches.&lt;/p&gt;

&lt;p&gt;A note before you go build this. Everything here is what I've used, shared as is. It's not vetted for your setup, and I can't vouch for the security of tools I didn't write. Read the code, test it somewhere safe, and decide for yourself. Useful to me isn't the same as safe for you. That part's on you to check.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published &lt;a href="https://x.com/acolombiadev/status/2067790524451266988" rel="noopener noreferrer"&gt;on X&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>multiagent</category>
      <category>githubcopilot</category>
      <category>developertools</category>
    </item>
    <item>
      <title>Stop paying for the same tokens twice</title>
      <dc:creator>Andrea Liliana Griffiths</dc:creator>
      <pubDate>Fri, 19 Jun 2026 14:04:04 +0000</pubDate>
      <link>https://dev.to/andreagriffiths11/stop-paying-for-the-same-tokens-twice-geh</link>
      <guid>https://dev.to/andreagriffiths11/stop-paying-for-the-same-tokens-twice-geh</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;I ran five reviewer agents over a 16K-token PR. The naive setup cost $1.32. Two architectural changes brought it to $0.49. Here's the bill, and what the experiment surprised me with along the way.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Five specialist agents reviewed the same pull request. Security, tests, perf, observability, API design. Each one re-read the full diff. Each one paid full price. The bill landed at $1.32 for a single PR pass on Claude Opus 4.6.&lt;/p&gt;

&lt;p&gt;One PR. One review pass. Buck thirty-two.&lt;/p&gt;

&lt;p&gt;If you're running multi-agent code review at any scale, you're bleeding money on the exact same tokens, over and over, paid in full each time.&lt;/p&gt;

&lt;p&gt;I built a harness to measure the bleed and test the two obvious fixes. The numbers were sharper than I expected, and one of them inverted my assumptions about prompt caching.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I built
&lt;/h2&gt;

&lt;p&gt;A small Python harness with three modes and one shared 49K-character pull request diff. Five reviewer roles, each with a tight system prompt:&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;REVIEWER_ROLES&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;security&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;Auth, injection, secrets, access control...&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;tests&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;Missing tests, skipped tests, weak assertions...&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;perf&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;N+1 queries, sync I/O in request paths...&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;observability&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;Logging hygiene, error handling, missing metrics...&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;api-design&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;Endpoint naming, status codes, idempotency...&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;Three modes against the same diff:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Naive.&lt;/strong&gt; Each reviewer makes its own call with the full diff in the user message. Role text comes first so the prefix differs per call. Nothing gets cached.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cache.&lt;/strong&gt; Each reviewer puts the diff in the system message, identical across all five calls. The first call writes to the provider's prompt cache. Calls two through five read from it at a 90% discount.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Librarian.&lt;/strong&gt; A first pass digests the diff into a compact JSON summary. Reviewers run against the digest, not the raw diff. Inspired by Cho et al.'s arXiv paper &lt;a href="https://arxiv.org/abs/2605.27787" rel="noopener noreferrer"&gt;Long Live the Librarian!&lt;/a&gt;, which uses a persistent search sub-agent to suppress redundant exploration tokens across agents.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I priced every call at Anthropic's API list rates: $15/M input, $1.50/M cache reads, $75/M output. Real measured token counts, list-price arithmetic on top.&lt;/p&gt;

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

&lt;p&gt;Large diff (49K characters, roughly 16K tokens per call), five reviewers, single fresh review pass:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mode&lt;/th&gt;
&lt;th&gt;Input&lt;/th&gt;
&lt;th&gt;Cached&lt;/th&gt;
&lt;th&gt;Output&lt;/th&gt;
&lt;th&gt;Total&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Naive&lt;/td&gt;
&lt;td&gt;80,248&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1,500&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$1.316&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cache&lt;/td&gt;
&lt;td&gt;80,268&lt;/td&gt;
&lt;td&gt;63,968 (4/5 calls)&lt;/td&gt;
&lt;td&gt;1,500&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$0.453&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Librarian&lt;/td&gt;
&lt;td&gt;20,915&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;2,300&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$0.486&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Naive is comically wasteful. Cache and librarian both cut it by roughly two thirds.&lt;/p&gt;

&lt;p&gt;Cache edges librarian by three cents. That's real, and it changes how I think about which lever to pull first.&lt;/p&gt;

&lt;h2&gt;
  
  
  When caching actually beats the librarian
&lt;/h2&gt;

&lt;p&gt;Caching wins on a warm series. The first call writes to cache, the next four read from it. If you can guarantee five reviewers run back-to-back against the same shared prefix in the same warm session, prompt caching is the cleanest move you can make. Two-line system message refactor. 66% off the bill.&lt;/p&gt;

&lt;p&gt;The problem: code review bots almost never run that way in production.&lt;/p&gt;

&lt;p&gt;Each PR is a fresh session. PRs come in from different developers, different repos, different branches, at unpredictable intervals. There's no "warm series." There's a parade of cold starts.&lt;/p&gt;

&lt;p&gt;When every call is cold, cache mode collapses back to naive mode. Same dollars per call. Same bleed.&lt;/p&gt;

&lt;p&gt;The librarian pattern doesn't care whether the session is warm or cold. Each reviewer reads a tiny digest, not the raw diff. The savings are baked into the shape of the calls, not the runtime state of a cache somewhere in the provider's fleet.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mode&lt;/th&gt;
&lt;th&gt;Warm series (5 calls back-to-back)&lt;/th&gt;
&lt;th&gt;Cold every call (operational reality)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Naive&lt;/td&gt;
&lt;td&gt;$1.32&lt;/td&gt;
&lt;td&gt;$1.32&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cache&lt;/td&gt;
&lt;td&gt;$0.45&lt;/td&gt;
&lt;td&gt;$1.32&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Librarian&lt;/td&gt;
&lt;td&gt;$0.49&lt;/td&gt;
&lt;td&gt;$0.49&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If your reviewers run in tight bursts inside a single session, cache. If they run independently across cold starts, use the librarian. Most real systems are the second kind.&lt;/p&gt;

&lt;h2&gt;
  
  
  What surprised me about caching
&lt;/h2&gt;

&lt;p&gt;I built the harness with a fail-loud guardrail. If calls 2 through N in cache mode report zero cached tokens, the harness aborts and prints diagnostics. The cached prefix should hit, and if it doesn't, the experiment is invalid.&lt;/p&gt;

&lt;p&gt;It tripped twice on the small-diff run.&lt;/p&gt;

&lt;p&gt;Same code, same five-call sequence, same identical system message at 4,003 tokens. Both runs returned &lt;code&gt;cached_tokens=0&lt;/code&gt; for every single call. Cache mode and naive mode came in at the exact same $0.413, to four decimal places.&lt;/p&gt;

&lt;p&gt;Then I ran the large diff at 16,000 tokens per call. Four out of five calls hit the cache cleanly. 15,992 cached tokens each.&lt;/p&gt;

&lt;p&gt;So somewhere between 4K and 16K tokens of identical prefix, against &lt;code&gt;claude-opus-4.6&lt;/code&gt; through the Copilot proxy with an OpenAI-shape request, prompt caching activates. Below that threshold, it doesn't. The Anthropic docs say the minimum is roughly 1024 to 2048 tokens. Empirically, the activation curve is not flat.&lt;/p&gt;

&lt;p&gt;If you're budgeting on a stated cache discount, model your hit rate as a band. Run the experiment on your actual payload sizes. Don't assume the marketing math holds for the call shapes you're actually making.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it yourself
&lt;/h2&gt;

&lt;p&gt;The full harness lives at &lt;a href="https://github.com/AndreaGriffiths11/librarian-demo" rel="noopener noreferrer"&gt;github.com/AndreaGriffiths11/librarian-demo&lt;/a&gt;. Three Python files, one diff scenario, one pricing module. Run it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;COPILOT_OAUTH_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;sqlite3 ~/.copilot/data.db &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"SELECT access_token FROM github_accounts WHERE is_default=1;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

python demo.py all &lt;span class="nt"&gt;--verbose&lt;/span&gt; &lt;span class="nt"&gt;--diff&lt;/span&gt; scenario/sample_pr_large.diff
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you have the GitHub Copilot CLI installed, you already have an OAuth token sitting in &lt;code&gt;~/.copilot/data.db&lt;/code&gt;. Point the OpenAI SDK at &lt;code&gt;https://api.githubcopilot.com&lt;/code&gt; with the &lt;code&gt;Copilot-Integration-Id: copilot-cli&lt;/code&gt; header and you get the full model catalog (Anthropic, OpenAI, Google) on the chat-completions shape, with &lt;code&gt;prompt_tokens_details.cached_tokens&lt;/code&gt; reporting. No PAT, no token exchange. About 30 lines of glue:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sqlite3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pathlib&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OpenAI&lt;/span&gt;

&lt;span class="n"&gt;con&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sqlite3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&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;file:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;pathlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;home&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/.copilot/data.db?mode=ro&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;uri&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;con&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SELECT access_token FROM github_accounts WHERE is_default=1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;fetchone&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;base_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.githubcopilot.com&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;default_headers&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;Copilot-Integration-Id&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;copilot-cli&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;One billing note: GitHub Copilot moves to usage-based billing on June 1, 2026. Under the new model, token consumption maps directly to GitHub AI Credits at Anthropic's published API rates, so the dollar figures in this article apply to Copilot users now too, not just people hitting the API directly. The architectural takeaway is the same either way. If you're on a paid Copilot plan, these savings are real dollars out of your monthly credit allotment.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'd actually ship
&lt;/h2&gt;

&lt;p&gt;If I were rebuilding a review pipeline tomorrow with this data on the table:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Move all shared context into the system message. It's the cheapest refactor in software, and it costs you nothing when the cache doesn't activate.&lt;/li&gt;
&lt;li&gt;Build the librarian pass once you cross three reviewers, or once your shared context is large enough that the activation threshold actually kicks in. The digest pays for itself across cold sessions.&lt;/li&gt;
&lt;li&gt;Stop treating cache hit rate as a constant. Measure it on your payloads, in your environment, against the model you ship with. Write a fail-loud guardrail and let it scream when assumptions break.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Cho et al.'s paper measures GPU energy savings on SWE-Bench Verified, up to 25% on multi-agent runs. My harness measures wall-clock dollars on one PR review pass. Different proxy, same lesson: persistent shared context across agents is a free architectural lever sitting on the floor.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Paper: Cho, Choi, Heo, Choi. &lt;a href="https://arxiv.org/abs/2605.27787" rel="noopener noreferrer"&gt;"Long Live the Librarian! A Persistent Search Sub-Agent for Energy-Efficient Multi-Agent Software Engineering Systems"&lt;/a&gt; (arXiv:2605.27787, May 2026).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;All numbers measured against &lt;code&gt;claude-opus-4.6&lt;/code&gt; via the GitHub Copilot proxy on May 29, 2026. Full per-call breakdowns and the harness source live in the &lt;a href="https://github.com/AndreaGriffiths11/librarian-demo/blob/main/runs/findings.md" rel="noopener noreferrer"&gt;&lt;code&gt;runs/findings.md&lt;/code&gt;&lt;/a&gt; of the repo.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>multiagent</category>
      <category>promptcaching</category>
      <category>codereview</category>
    </item>
    <item>
      <title>I Gave My Newsletter a Voice (Literally)</title>
      <dc:creator>Andrea Liliana Griffiths</dc:creator>
      <pubDate>Sat, 09 May 2026 10:48:10 +0000</pubDate>
      <link>https://dev.to/andreagriffiths11/i-gave-my-newsletter-a-voice-literally-3k5p</link>
      <guid>https://dev.to/andreagriffiths11/i-gave-my-newsletter-a-voice-literally-3k5p</guid>
      <description>&lt;h1&gt;
  
  
  I Gave My Newsletter a Voice (Literally)
&lt;/h1&gt;

&lt;p&gt;My newsletter site has a chat widget now. You type a question, it searches through every issue I've ever written, and gives you an answer with sources.&lt;/p&gt;

&lt;p&gt;That took an evening. Cool, but not interesting enough to write about.&lt;/p&gt;

&lt;p&gt;What made me write this: I added a microphone button next to the text input. Click it, and you're in a real-time voice conversation with an AI agent that knows my content. You talk, it listens, it talks back. Not a recording. Not text-to-speech over a chat response. An actual voice conversation.&lt;/p&gt;

&lt;p&gt;The stack behind it is LiveKit, and I want to walk through how it works because it's simpler than I expected.&lt;/p&gt;

&lt;h2&gt;
  
  
  What LiveKit Actually Does
&lt;/h2&gt;

&lt;p&gt;LiveKit is real-time communication infrastructure. Think "Zoom but programmable." It handles all the WebRTC complexity — rooms, audio routing, codecs, latency optimization — so you don't have to.&lt;/p&gt;

&lt;p&gt;The part that matters for AI voice agents: LiveKit has an agent framework. You write a Python worker that connects to their cloud service and waits. When a user joins a room, LiveKit dispatches your agent into that room. The agent listens to the user's microphone, processes speech, thinks, and talks back. All in real time.&lt;/p&gt;

&lt;p&gt;The latency is wild. It feels like talking to someone, not waiting for a computer.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Architecture
&lt;/h2&gt;

&lt;p&gt;Three pieces:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The API&lt;/strong&gt; — A FastAPI server that handles text chat (RAG search over my newsletter content) and generates LiveKit room tokens when someone clicks the mic button.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The voice agent&lt;/strong&gt; — A Python worker running LiveKit's agent SDK. It connects outbound to LiveKit Cloud and waits for rooms. When someone joins, it gets dispatched. Inside the agent: voice activity detection (Silero VAD), speech-to-text (Azure Speech Services), an LLM (GPT-4.1-mini via GitHub Models), and text-to-speech (Azure Speech Services). Azure handles both ends of the voice pipeline — turning your speech into text the LLM can understand, then turning the LLM's response back into natural-sounding speech. Before every response, it searches my knowledge base for relevant context — same RAG pipeline the text chat uses.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The frontend&lt;/strong&gt; — An Astro component with a mic button. Clicking it loads the LiveKit client SDK, requests a room token from my API, and connects to the room via WebRTC. The agent joins, and they're talking.&lt;/p&gt;

&lt;p&gt;Both the API and the voice agent run in a single Railway container. A bash script starts both processes — if either dies, the container exits and Railway restarts it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The RAG Part
&lt;/h2&gt;

&lt;p&gt;Every time the user says something, the agent:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Transcribes the speech — Azure Speech Services converts your voice to text in real time&lt;/li&gt;
&lt;li&gt;Embeds the transcript using GitHub Models API (text-embedding-3-small, 1536 dimensions)&lt;/li&gt;
&lt;li&gt;Searches a SQLite vector database (sqlite-vec) for the most relevant newsletter chunks&lt;/li&gt;
&lt;li&gt;Rebuilds the system prompt with fresh context&lt;/li&gt;
&lt;li&gt;Generates a response (GPT-4.1-mini via GitHub Models)&lt;/li&gt;
&lt;li&gt;Speaks it back — Azure Speech Services (en-US-JennyNeural voice) converts the text response to natural-sounding speech&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This happens per utterance. The agent's knowledge stays current with whatever the user is asking about, not stuck on whatever the first question was.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The hybrid retrieval trick:&lt;/strong&gt; Vector search alone can't answer "what's the latest issue?" because semantic similarity doesn't understand ordering. The solution: at startup, the agent queries the database for all newsletter issue URLs, extracts the numbers, and injects a content index into every system prompt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Available newsletter issues: issue-1, issue-2, ..., issue-20
The latest/most recent issue is issue-20
Total issues: 20
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the LLM gets both semantic context from vector search &lt;em&gt;and&lt;/em&gt; structural metadata it can't learn from embeddings. Ask "what's the latest issue?" and it knows. Ask "tell me about GitHub Copilot" and vector search finds the right chunks. Hybrid retrieval.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Azure Speech Services?
&lt;/h2&gt;

&lt;p&gt;The voice pipeline has two critical pieces where quality matters:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Speech-to-text accuracy.&lt;/strong&gt; If the transcription is wrong, the whole conversation breaks. Azure Speech Services gives me high-accuracy transcription with low latency — critical for real-time voice. It handles accents, background noise, and technical terminology better than the alternatives I tested.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Natural-sounding TTS.&lt;/strong&gt; Azure's neural voices sound human. Not robotic, not uncanny valley. The "en-US-JennyNeural" voice I use for the agent has natural pacing, intonation, and emotion. When the agent says "Let me search my knowledge base for that," it sounds like a person helping you, not a computer reading text.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Streaming support.&lt;/strong&gt; Both Azure STT and TTS support streaming. The agent starts transcribing as you speak (no waiting for you to finish), and starts speaking as soon as the first chunk of TTS audio is ready (no waiting for the full LLM response). This cuts perceived latency in half.&lt;/p&gt;

&lt;p&gt;LiveKit integrates with Azure Speech Services out of the box via their plugins (&lt;code&gt;livekit-plugins-azure&lt;/code&gt;). Configuration is straightforward — set your Azure subscription key and region, pick a voice, done.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Surprised Me
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;LiveKit agents are workers, not servers.&lt;/strong&gt; They don't listen on a port. They connect outbound to LiveKit Cloud and get dispatched into rooms. This threw me at first — I kept trying to think of it as another HTTP service. It's not. It's a background worker that happens to handle real-time audio.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The voice pipeline has real latency requirements.&lt;/strong&gt; Text chat can take 2-3 seconds and nobody cares. Voice? If there's a 2-second gap after someone finishes talking, it feels broken. LiveKit's streaming architecture handles this — the TTS starts speaking before the full LLM response is complete.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;sqlite-vec is underrated.&lt;/strong&gt; I'm running vector search in SQLite. No Pinecone, no Weaviate, no managed vector database. For a knowledge base of ~130 newsletter chunks (all 20 issues, articles, and GitHub blog posts), this is more than enough. The query takes single-digit milliseconds. Embeddings come from GitHub Models API during ingestion — free during preview, high quality (text-embedding-3-small, 1536 dims), and no local model loading headaches.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Debugging production is different.&lt;/strong&gt; The voice agent worked locally but failed silently in Railway. The agent would listen, transcribe perfectly, but always respond with "I don't have that information." Turned out the embeddings API was returning 400 errors because an old environment variable (&lt;code&gt;LIVEBRAIN_EMBEDDING_MODEL&lt;/code&gt;) was still set to a local model name (&lt;code&gt;all-MiniLM-L6-v2&lt;/code&gt;) that the API didn't recognize. The fix: delete the variable and let it default to &lt;code&gt;text-embedding-3-small&lt;/code&gt;. Real-time logging made this visible — without &lt;code&gt;print()&lt;/code&gt; statements showing chunk retrieval counts and similarities, I would have been guessing for hours.&lt;/p&gt;

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

&lt;p&gt;I'm extracting the reusable parts of this into an open-source framework. The idea: point it at a YAML file with your content sources, run an ingestion script, and you get a voice agent that knows your stuff. Newsletter, documentation, blog — whatever you feed it.&lt;/p&gt;

&lt;p&gt;It's not ready yet. The mainbranch-agent version works, but the generic framework needs cleanup before anyone else can use it. I'll open-source it when it's actually good, not when it's "minimum viable."&lt;/p&gt;

&lt;p&gt;If you want to see it in action, go to &lt;a href="https://mainbranch.dev" rel="noopener noreferrer"&gt;mainbranch.dev&lt;/a&gt; and click the chat bubble. The mic button is right there.&lt;/p&gt;

</description>
      <category>livekit</category>
      <category>voiceai</category>
      <category>rag</category>
      <category>githubmodels</category>
    </item>
    <item>
      <title>Debug GitHub Actions from Your Terminal with gh</title>
      <dc:creator>Andrea Liliana Griffiths</dc:creator>
      <pubDate>Sat, 09 May 2026 10:44:56 +0000</pubDate>
      <link>https://dev.to/andreagriffiths11/debug-github-actions-from-your-terminal-with-gh-3af5</link>
      <guid>https://dev.to/andreagriffiths11/debug-github-actions-from-your-terminal-with-gh-3af5</guid>
      <description>&lt;h1&gt;
  
  
  Debug GitHub Actions from Your Terminal with &lt;code&gt;gh&lt;/code&gt;
&lt;/h1&gt;

&lt;p&gt;If your GitHub Actions debugging workflow starts with opening three browser tabs, it is probably slower than it needs to be.&lt;/p&gt;

&lt;p&gt;Most CI failures do not require the Actions UI at all. The &lt;code&gt;gh&lt;/code&gt; CLI gives you the core loop from your terminal: find the broken run, read the failure, retry it, and watch it live. Once you get used to it, going back to the browser feels clumsy.&lt;/p&gt;




&lt;h2&gt;
  
  
  Find the run
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh run list &lt;span class="nt"&gt;--limit&lt;/span&gt; 10
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Start here. This shows recent runs, their status, and what triggered them.&lt;/p&gt;

&lt;p&gt;If a workflow has been stuck in &lt;code&gt;queued&lt;/code&gt; forever, you will see it immediately. If you want to script against the output, add &lt;code&gt;--json&lt;/code&gt; and skip the copy-paste routine entirely.&lt;/p&gt;




&lt;h2&gt;
  
  
  Read only what failed
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh run view &amp;lt;run-id&amp;gt; &lt;span class="nt"&gt;--log-failed&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the command I was missing.&lt;/p&gt;

&lt;p&gt;You do not always need the full log dump. You usually need the failing step. &lt;code&gt;--log-failed&lt;/code&gt; cuts straight to the useful part, which matters a lot once your workflow grows past a handful of jobs.&lt;/p&gt;

&lt;p&gt;If you do need everything, switch to &lt;code&gt;--log&lt;/code&gt;. If you are debugging a matrix build, pipe the output into &lt;code&gt;grep&lt;/code&gt; and keep moving.&lt;/p&gt;




&lt;h2&gt;
  
  
  Retry only the broken part
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh run rerun &amp;lt;run-id&amp;gt; &lt;span class="nt"&gt;--failed&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This reruns only the jobs that failed, plus anything they depend on. That is usually what you want.&lt;/p&gt;

&lt;p&gt;If the failure came from a flaky test, a registry timeout, or some other transient CI nonsense, rerunning the entire workflow is just wasted time and compute.&lt;/p&gt;

&lt;p&gt;One gotcha: you cannot rerun a workflow while it is still in progress. The CLI can return an error that makes it sound like the workflow file is invalid. In practice, it often just means the run has not finished yet.&lt;/p&gt;

&lt;p&gt;If you want to rerun one specific job, get the correct ID first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh run view &amp;lt;run-id&amp;gt; &lt;span class="nt"&gt;--json&lt;/span&gt; &lt;span class="nb"&gt;jobs&lt;/span&gt; &lt;span class="nt"&gt;--jq&lt;/span&gt; &lt;span class="s1"&gt;'.jobs[] | {name, databaseId}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use &lt;code&gt;databaseId&lt;/code&gt; with &lt;code&gt;--job&lt;/code&gt;. Do not trust yourself to grab a random number from the web UI and hope it matches what the CLI expects.&lt;/p&gt;




&lt;h2&gt;
  
  
  Watch it live
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh run watch &amp;lt;run-id&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This streams the run as it happens. It is the closest thing to &lt;code&gt;tail -f&lt;/code&gt; for Actions, and it is a lot nicer than refreshing the browser every 20 seconds.&lt;/p&gt;

&lt;p&gt;If you live in the terminal already, this feels like the missing piece.&lt;/p&gt;




&lt;h2&gt;
  
  
  Trigger a run without pushing a commit
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh workflow run &amp;lt;workflow-file&amp;gt;.yml &lt;span class="nt"&gt;--ref&lt;/span&gt; &amp;lt;branch&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If a workflow supports &lt;code&gt;workflow_dispatch&lt;/code&gt;, use it. It is one of the simplest ways to test workflow changes without creating throwaway commits just to poke CI.&lt;/p&gt;

&lt;p&gt;If your workflow does not expose &lt;code&gt;workflow_dispatch&lt;/code&gt;, that is worth fixing. Manual triggers make debugging easier and demos cleaner.&lt;/p&gt;




&lt;h2&gt;
  
  
  The 403 that wastes too much time
&lt;/h2&gt;

&lt;p&gt;A surprising number of Actions failures come down to one thing: &lt;code&gt;GITHUB_TOKEN&lt;/code&gt; does not have the permission your workflow needs, and the error message is usually less clear than it should be.&lt;/p&gt;

&lt;p&gt;If your workflow needs to write to the repository or update a pull request, declare permissions explicitly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;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;write&lt;/span&gt;
  &lt;span class="na"&gt;pull-requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do not rely on defaults and then act surprised when a write fails halfway through automation. Ask for the minimum you need, on purpose.&lt;/p&gt;




&lt;h2&gt;
  
  
  The loop I actually use
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh run list                       &lt;span class="c"&gt;# find the run&lt;/span&gt;
gh run view &amp;lt;run-id&amp;gt; &lt;span class="nt"&gt;--log-failed&lt;/span&gt; &lt;span class="c"&gt;# read the failure&lt;/span&gt;
gh run rerun &amp;lt;run-id&amp;gt; &lt;span class="nt"&gt;--failed&lt;/span&gt;    &lt;span class="c"&gt;# retry only what broke&lt;/span&gt;
gh run watch &amp;lt;run-id&amp;gt;             &lt;span class="c"&gt;# follow the rerun live&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is enough for a big chunk of day-to-day Actions debugging. The browser still has its place, but it does not need to be your default.&lt;/p&gt;

&lt;p&gt;Full reference: &lt;a href="https://cli.github.com/manual/gh_run" rel="noopener noreferrer"&gt;cli.github.com/manual/gh_run&lt;/a&gt;&lt;/p&gt;

</description>
      <category>githubactions</category>
      <category>ghcli</category>
      <category>cicd</category>
      <category>developertools</category>
    </item>
    <item>
      <title>GitHub Actions: The Stuff Nobody Tells You</title>
      <dc:creator>Andrea Liliana Griffiths</dc:creator>
      <pubDate>Sun, 05 Apr 2026 12:39:48 +0000</pubDate>
      <link>https://dev.to/andreagriffiths11/github-actions-the-stuff-nobody-tells-you-19md</link>
      <guid>https://dev.to/andreagriffiths11/github-actions-the-stuff-nobody-tells-you-19md</guid>
      <description>&lt;h1&gt;
  
  
  GitHub Actions: The Stuff Nobody Tells You
&lt;/h1&gt;

&lt;p&gt;I work at GitHub. I use Actions every day. I've also debugged YAML at 2am, watched the log viewer eat my browser, and pushed a bunch of commits in a row just to figure out why a conditional wasn't evaluating correctly.&lt;/p&gt;

&lt;p&gt;I'm not here to tell you Actions is perfect. It's not. The log viewer has made grown engineers question their career choices. The YAML expression syntax has a learning curve that feels more like a learning cliff. The push-wait-fail-repeat debugging loop can turn a five-minute fix into an afternoon-long hostage situation.&lt;/p&gt;

&lt;p&gt;I know this because I've lived it. And I've watched thousands of developers live it too.&lt;/p&gt;

&lt;p&gt;But here's what I've also seen: most of the pain comes from patterns that are avoidable. Not all of it. Some of it is the platform catching up. But a lot of it is stuff that has solutions right now that people haven't discovered yet because the easy path is to just keep copy-pasting YAML and suffering.&lt;/p&gt;

&lt;p&gt;This article is the stuff I wish someone had told me on day one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stop Using the Log Viewer
&lt;/h2&gt;

&lt;p&gt;I'm serious. The web UI for reading build logs is the single biggest source of frustration with Actions, and the fastest fix is to stop using it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh run view &lt;span class="nt"&gt;--log-failed&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. Failed step, in your terminal, instantly. No clicking through three pages. No waiting for the browser to decide whether it wants to render today. No back button roulette.&lt;/p&gt;

&lt;p&gt;If you want the full log:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh run view &lt;span class="nt"&gt;--log&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to watch a run in real time:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh run watch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The CLI is faster, searchable with grep, and doesn't crash when your test suite outputs 50,000 lines. If you're still clicking through the web UI to read build logs in 2026, this is your sign to stop.&lt;/p&gt;

&lt;h2&gt;
  
  
  The YAML Problem Is Real. Here's How to Shrink It.
&lt;/h2&gt;

&lt;p&gt;Every CI system ends up as "a bunch of YAML." Actions is no exception. But there's a difference between a 40-line workflow that does one thing clearly and a 400-line monster with nested conditionals, matrix strategies, and inline bash scripts that would make a shell programmer cry.&lt;/p&gt;

&lt;p&gt;The 400-line monster happens because people don't know about the two features designed to prevent it. Or they don't use them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reusable Workflows
&lt;/h3&gt;

&lt;p&gt;If you have the same CI steps across multiple repos, you're probably copy-pasting workflows. Stop.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# .github/workflows/ci.yml&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&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;your-org/.github/.github/workflows/build.yml@main&lt;/span&gt;  &lt;span class="c1"&gt;# @main is fine for internal repos you control — but if you SHA-pin everything else, consider pinning this too&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;20'&lt;/span&gt;
    &lt;span class="na"&gt;secrets&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;inherit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One workflow, maintained in one place, called from everywhere. When you update it, every repo that uses it gets the update. No drift. No "wait, which repo has the latest version of our deploy script?"&lt;/p&gt;

&lt;h3&gt;
  
  
  Composite Actions
&lt;/h3&gt;

&lt;p&gt;Reusable workflows are for whole pipelines. Composite actions are for steps, the building blocks.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# .github/actions/setup-project/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;Project'&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;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f&lt;/span&gt; &lt;span class="c1"&gt;# v6.3.0&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="pi"&gt;-&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;span class="pi"&gt;-&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;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;p&gt;Now your workflow files read like sentences, not telenovelas:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;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@de0fac2e4500dabe0009e67214ff5f5447ce83dd&lt;/span&gt; &lt;span class="c1"&gt;# v6.0.2&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;./.github/actions/setup-project&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;20'&lt;/span&gt;
  &lt;span class="pi"&gt;-&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;p&gt;The YAML is still there. But it's 12 lines, not 120. And when setup changes, you change it in one place.&lt;/p&gt;

&lt;h2&gt;
  
  
  Break the Push-Wait-Fail Loop
&lt;/h2&gt;

&lt;p&gt;The most soul-crushing part of Actions debugging: you make a one-character change to a workflow file, push it, wait four minutes for a runner to spin up, and find out you missed a quote. A bunch of commits later, your git history looks like a cry for help.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/nektos/act" rel="noopener noreferrer"&gt;&lt;code&gt;act&lt;/code&gt;&lt;/a&gt;, a community-maintained tool, runs your workflows locally in Docker containers. Same environment, no push required.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;act &lt;span class="nt"&gt;-j&lt;/span&gt; build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's not a perfect replica. Some GitHub-specific contexts don't exist locally. But for "did I break the YAML" and "does my bash script actually work," it cuts that feedback loop from minutes to seconds.&lt;/p&gt;

&lt;p&gt;For simple syntax validation before you even run anything:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh workflow view ci.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the YAML has obvious issues, it'll surface them quickly. It's not a full linter, but it catches the basics without a push cycle.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Marketplace Trust Problem (and What to Do About It)
&lt;/h2&gt;

&lt;p&gt;Every &lt;code&gt;uses: some-stranger/cool-action@v2&lt;/code&gt; is code you didn't write running with access to your repo and secrets. That's a real security concern, and "just pin to a SHA" is the right answer that nobody follows.&lt;/p&gt;

&lt;p&gt;Here's what actually works:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Pin to SHAs and let Dependabot manage updates:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&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@de0fac2e4500dabe0009e67214ff5f5447ce83dd&lt;/span&gt; &lt;span class="c1"&gt;# v6.0.2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the version in a comment so humans can read it. Dependabot will open PRs when new versions drop, and you can review the diff before updating. &lt;em&gt;(SHAs in this article were verified on March 30, 2026.)&lt;/em&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Stick to GitHub-maintained actions when possible. &lt;code&gt;actions/checkout&lt;/code&gt;, &lt;code&gt;actions/setup-node&lt;/code&gt;, &lt;code&gt;actions/cache&lt;/code&gt; — these are maintained by the same team that builds the platform. They're audited, tested, and updated.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;For everything else, read the source. It's open source. If a marketplace action is a 20-line shell script wrapped in a Dockerfile, maybe just copy the 20 lines into a &lt;code&gt;run:&lt;/code&gt; step and own it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use OpenSSF Scorecard to assess action maintainer practices before adopting.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conditional Logic Without Losing Your Mind
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;${{ }}&lt;/code&gt; expression syntax is one of those things that's simple until it isn't, and then it's baffling. The edge cases around string interpolation, truthiness, and type coercion have bitten everyone at least once.&lt;/p&gt;

&lt;p&gt;A few survival rules:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Always quote expressions in `if:`&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.event_name == 'push' }}&lt;/span&gt;

&lt;span class="c1"&gt;# Use fromJSON for booleans from inputs&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;${{ fromJSON(inputs.deploy) == &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="s"&gt; }}&lt;/span&gt;

&lt;span class="c1"&gt;# Multi-condition? Use &amp;gt;- to fold newlines into spaces.&lt;/span&gt;
&lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;&amp;gt;-&lt;/span&gt;
  &lt;span class="s"&gt;${{ github.ref == 'refs/heads/main' &amp;amp;&amp;amp;&lt;/span&gt;
      &lt;span class="s"&gt;github.event_name == 'push' }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And if your conditional logic is getting complex enough to need a flowchart, that's a sign you need a &lt;a href="https://docs.github.com/en/actions/sharing-automations/reusing-workflows" rel="noopener noreferrer"&gt;reusable workflow with inputs&lt;/a&gt;, not more &lt;code&gt;if:&lt;/code&gt; statements.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://docs.github.com/en/actions/reference/workflows-and-actions/expressions#case" rel="noopener noreferrer"&gt;&lt;code&gt;case()&lt;/code&gt; function&lt;/a&gt; is a recent addition worth knowing about. Think of it as a switch statement for expressions. It replaces nested ternaries that nobody can read.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let Copilot Write the YAML
&lt;/h2&gt;

&lt;p&gt;I'm not going to pretend the YAML is fun to write. But in 2026, you don't have to write most of it.&lt;/p&gt;

&lt;p&gt;In VS Code with GitHub Copilot, describe what you want in a comment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Deploy to production on push to main, run tests first,&lt;/span&gt;
&lt;span class="c1"&gt;# cache node_modules, notify Slack on failure&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copilot generates the workflow. You review and adjust. It handles the syntax, the &lt;code&gt;on:&lt;/code&gt; triggers, the &lt;code&gt;runs-on:&lt;/code&gt;, the step ordering, so you focus on what the pipeline should &lt;em&gt;do&lt;/em&gt;, not on remembering whether &lt;code&gt;environment&lt;/code&gt; goes inside or outside &lt;code&gt;jobs:&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For existing workflows, Copilot agent mode can refactor a 400-line YAML file into reusable workflows and composite actions. Tell it what you want, review the PR.&lt;/p&gt;

&lt;p&gt;This doesn't fix Actions. It fixes you having to wrestle with it directly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Caching: The Free Speed You're Probably Not Using
&lt;/h2&gt;

&lt;p&gt;If your workflow installs dependencies on every run and you haven't set up caching, you're leaving minutes on the table for free.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f&lt;/span&gt; &lt;span class="c1"&gt;# v6.3.0&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;20'&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;TThat one line — &lt;code&gt;cache: 'npm'&lt;/code&gt; — tells &lt;code&gt;setup-node&lt;/code&gt; to cache your &lt;code&gt;node_modules&lt;/code&gt; between runs. First run is normal. Every run after that skips the full &lt;code&gt;npm ci&lt;/code&gt; download. For large projects, this cuts two to four minutes off every build.&lt;/p&gt;

&lt;p&gt;The same pattern works for other ecosystems:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Python&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/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405&lt;/span&gt; &lt;span class="c1"&gt;# v6.2.0&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.12'&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;pip'&lt;/span&gt;

&lt;span class="c1"&gt;# Go (manual cache)&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/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7&lt;/span&gt; &lt;span class="c1"&gt;# v5.0.4&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;~/go/pkg/mod&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 }}-go-${{ hashFiles('**/go.sum') }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you need more control, &lt;code&gt;actions/cache&lt;/code&gt; lets you cache anything — build artifacts, Docker layers, compiled binaries. The key is hashing your lockfile so the cache invalidates when dependencies actually change.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stop Running the Same Workflow Twice
&lt;/h2&gt;

&lt;p&gt;If your team pushes fast, you've probably seen this: three commits in ten minutes, three workflow runs queued, the first two are already stale by the time they finish.&lt;/p&gt;

&lt;p&gt;Concurrency groups fix this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;concurrency&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;group&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ github.workflow }}-${{ github.ref }}&lt;/span&gt;
  &lt;span class="na"&gt;cancel-in-progress&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add this at the top level of your workflow. Same branch, same workflow — the old run gets cancelled when a new one starts. No more wasting runner minutes on commits that are already superseded.&lt;/p&gt;

&lt;p&gt;This is especially useful for PR workflows where developers are iterating quickly. Without it, you're paying for builds nobody will look at.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Actually Getting Better
&lt;/h2&gt;

&lt;p&gt;I said I wouldn't sugarcoat this, so let me be specific about what's improved and what still needs work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Better now:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Job summaries, structured output instead of just log lines&lt;/li&gt;
&lt;li&gt;Larger runners, 64-core machines available, ARM runners in GA&lt;/li&gt;
&lt;li&gt;Required workflow enforcement via rulesets, organization-wide policy without copy-paste&lt;/li&gt;
&lt;li&gt;Larger runners, 64-core machines available on paid plans (Team/Enterprise), ARM runners in GA for public repos&lt;/li&gt;
&lt;li&gt;Immutable actions, actions published to GHCR with provenance&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;case()&lt;/code&gt; and recent expression improvements&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Still needs work:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The log viewer. It's improved, but it's not where it needs to be for large builds. Use the CLI.&lt;/li&gt;
&lt;li&gt;Debugging experience. &lt;code&gt;act&lt;/code&gt; helps, but first-party local execution would change everything.&lt;/li&gt;
&lt;li&gt;The learning curve for expressions. The docs team has been steadily improving this, and it shows — but there's still room to grow.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'm not writing this to defend GitHub's honor. I'm writing it because I've watched too many teams suffer through problems that have solutions, and those solutions aren't reaching people fast enough.&lt;/p&gt;

&lt;p&gt;The fundamentals are there. The platform works. But "works" and "pleasant" are different things, and the gap between them is where your afternoon disappears. These patterns close that gap. Not all the way. But enough.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;🆕 Update:&lt;/strong&gt; I turned the patterns from this article into a reusable Copilot skill — a markdown file your AI coding agent can reference when writing workflows. It covers SHA pinning, matrix strategies, artifacts, permissions, timeouts, and the filesystem gotchas that eat your afternoon. Still testing it, but you can try it now: &lt;a href="https://mainbranch.dev/skills/github-actions.md" rel="noopener noreferrer"&gt;GitHub Actions Skill&lt;/a&gt;&lt;/p&gt;

</description>
      <category>githubactions</category>
      <category>cicd</category>
      <category>developertools</category>
      <category>fundamentals</category>
    </item>
    <item>
      <title>GitHub Copilot CLI Enhanced with Chronicle</title>
      <dc:creator>Andrea Liliana Griffiths</dc:creator>
      <pubDate>Sat, 28 Mar 2026 03:08:26 +0000</pubDate>
      <link>https://dev.to/andreagriffiths11/github-copilot-cli-enhanced-with-chronicle-27fk</link>
      <guid>https://dev.to/andreagriffiths11/github-copilot-cli-enhanced-with-chronicle-27fk</guid>
      <description>&lt;p&gt;&lt;a href="https://github.com/features/copilot" rel="noopener noreferrer"&gt;https://github.com/features/copilot&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>cli</category>
      <category>github</category>
      <category>productivity</category>
    </item>
    <item>
      <title>OpenClaw Just Passed React. Here's What the GitHub Star Leaderboard Actually Looks Like</title>
      <dc:creator>Andrea Liliana Griffiths</dc:creator>
      <pubDate>Thu, 26 Mar 2026 22:13:47 +0000</pubDate>
      <link>https://dev.to/andreagriffiths11/openclaw-just-passed-react-heres-what-the-github-star-leaderboard-actually-looks-like-1118</link>
      <guid>https://dev.to/andreagriffiths11/openclaw-just-passed-react-heres-what-the-github-star-leaderboard-actually-looks-like-1118</guid>
      <description>&lt;p&gt;&lt;a href="https://dev.to/andreagriffiths11/openclaw-just-passed-react-heres-what-the-github-star-leaderboard-actually-looks-like-3d5g"&gt;https://dev.to/andreagriffiths11/openclaw-just-passed-react-heres-what-the-github-star-leaderboard-actually-looks-like-3d5g&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>OpenClaw Just Passed React. GitHub Star Leaderboard Update.</title>
      <dc:creator>Andrea Liliana Griffiths</dc:creator>
      <pubDate>Thu, 26 Mar 2026 22:09:06 +0000</pubDate>
      <link>https://dev.to/andreagriffiths11/openclaw-just-passed-react-github-star-leaderboard-update-1k1g</link>
      <guid>https://dev.to/andreagriffiths11/openclaw-just-passed-react-github-star-leaderboard-update-1k1g</guid>
      <description>&lt;p&gt;&lt;a href="https://dev.to/andreagriffiths11/openclaw-just-passed-react-heres-what-the-github-star-leaderboard-actually-looks-like-3d5g"&gt;https://dev.to/andreagriffiths11/openclaw-just-passed-react-heres-what-the-github-star-leaderboard-actually-looks-like-3d5g&lt;/a&gt;&lt;/p&gt;

</description>
      <category>github</category>
      <category>news</category>
      <category>openclaw</category>
      <category>react</category>
    </item>
    <item>
      <title>OpenClaw Just Passed React. Here's What the GitHub Star Leaderboard Actually Looks Like.</title>
      <dc:creator>Andrea Liliana Griffiths</dc:creator>
      <pubDate>Thu, 26 Mar 2026 22:07:24 +0000</pubDate>
      <link>https://dev.to/andreagriffiths11/openclaw-just-passed-react-heres-what-the-github-star-leaderboard-actually-looks-like-3p7c</link>
      <guid>https://dev.to/andreagriffiths11/openclaw-just-passed-react-heres-what-the-github-star-leaderboard-actually-looks-like-3p7c</guid>
      <description>&lt;p&gt;&lt;a href="https://dev.to/andreagriffiths11/openclaw-just-passed-react-heres-what-the-github-star-leaderboard-actually-looks-like-3d5g"&gt;https://dev.to/andreagriffiths11/openclaw-just-passed-react-heres-what-the-github-star-leaderboard-actually-looks-like-3d5g&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>OpenClaw Just Passed React. Here's What the GitHub Star Leaderboard Actually Looks Like.</title>
      <dc:creator>Andrea Liliana Griffiths</dc:creator>
      <pubDate>Thu, 26 Mar 2026 22:01:44 +0000</pubDate>
      <link>https://dev.to/andreagriffiths11/openclaw-just-passed-react-heres-what-the-github-star-leaderboard-actually-looks-like-4dam</link>
      <guid>https://dev.to/andreagriffiths11/openclaw-just-passed-react-heres-what-the-github-star-leaderboard-actually-looks-like-4dam</guid>
      <description>&lt;p&gt;&lt;a href="https://dev.to/andreagriffiths11/openclaw-just-passed-react-heres-what-the-github-star-leaderboard-actually-looks-like-3d5g"&gt;https://dev.to/andreagriffiths11/openclaw-just-passed-react-heres-what-the-github-star-leaderboard-actually-looks-like-3d5g&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>A Rapper Tweeted About GitHub, So I Built Him a Learn-to-Code Repo from My Phone</title>
      <dc:creator>Andrea Liliana Griffiths</dc:creator>
      <pubDate>Wed, 25 Mar 2026 14:14:07 +0000</pubDate>
      <link>https://dev.to/andreagriffiths11/a-rapper-tweeted-about-github-so-i-built-him-a-learn-to-code-repo-from-my-phone-31d6</link>
      <guid>https://dev.to/andreagriffiths11/a-rapper-tweeted-about-github-so-i-built-him-a-learn-to-code-repo-from-my-phone-31d6</guid>
      <description>&lt;h1&gt;
  
  
  A Rapper Tweeted About GitHub, So I Built Him a Learn-to-Code Repo from My Phone
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://x.com/MeekMill/status/2036280155098751004" rel="noopener noreferrer"&gt;Meek Mill tweeted about GitHub.&lt;/a&gt; It was the middle of the night. I was in bed, half asleep, scrolling on my phone.&lt;/p&gt;

&lt;p&gt;So I messaged my AI agent from my phone, told it to build a learn-to-code repo for Meek Mill styled like album tracks, and it created the repo on GitHub and assigned the task to Copilot coding agent. Copilot wrote the content, structured the tracks, and opened a PR. I reviewed and merged from my phone.&lt;/p&gt;

&lt;p&gt;I never opened a terminal. Never opened an IDE.&lt;/p&gt;

&lt;p&gt;The repo: &lt;a href="https://github.com/AndreaGriffiths11/dreamchasers" rel="noopener noreferrer"&gt;dreamchasers&lt;/a&gt;. Six tracks plus a bonus, album format, each one teaching a real GitHub skill. Track 1 to first repo in 10 minutes. &lt;a href="https://x.com/acolombiadev/status/2036450986210841065" rel="noopener noreferrer"&gt;Here's the tweet.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A rapper with 10 million followers just put "GitHub" in front of people who have never heard of a pull request. Some kid scrolling past that tweet is going to think "wait, I can do that?" and the answer is yes.&lt;/p&gt;

&lt;p&gt;You don't need a CS degree. Don't need a bootcamp. Don't even need to leave your browser. Just &lt;a href="https://github.com/signup" rel="noopener noreferrer"&gt;a GitHub account&lt;/a&gt; and curiosity.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's New in Copilot CLI
&lt;/h2&gt;

&lt;p&gt;I wrote the &lt;a href="https://github.blog/ai-and-ml/github-copilot/github-copilot-cli-how-to-get-started/" rel="noopener noreferrer"&gt;official getting started guide&lt;/a&gt; back in October. A lot has changed since then.&lt;/p&gt;

&lt;h3&gt;
  
  
  It's Free
&lt;/h3&gt;

&lt;p&gt;Copilot CLI is included as a core feature of all GitHub Copilot plans: Free, Pro, Pro+, Business, and Enterprise. You get a free GitHub account, you get Copilot CLI. Each interaction uses premium requests from your plan's allowance (50/month on Free).&lt;/p&gt;

&lt;h3&gt;
  
  
  Three Modes: Ask, Plan, Autopilot
&lt;/h3&gt;

&lt;p&gt;Press Shift+Tab to cycle between modes:&lt;/p&gt;

&lt;p&gt;Ask/Execute mode is the default. You prompt, Copilot acts, you approve each step.&lt;/p&gt;

&lt;p&gt;Plan mode analyzes your request, asks clarifying questions, and builds a structured implementation plan before writing any code. Catches misunderstandings before they become bad commits.&lt;/p&gt;

&lt;p&gt;Autopilot mode carries the task forward without step-by-step approval. You outline the work, then let it run.&lt;/p&gt;

&lt;h3&gt;
  
  
  Model Agnostic
&lt;/h3&gt;

&lt;p&gt;Use &lt;code&gt;/model&lt;/code&gt; to switch between Claude, GPT, Gemini, and more. Switch mid-session. Run &lt;code&gt;/fleet&lt;/code&gt; to execute across multiple models in parallel.&lt;/p&gt;

&lt;h3&gt;
  
  
  Interactive and Programmatic
&lt;/h3&gt;

&lt;p&gt;Two interfaces:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Interactive:&lt;/strong&gt; Run &lt;code&gt;copilot&lt;/code&gt; and have a conversation. Use &lt;code&gt;/plan&lt;/code&gt; to outline work, &lt;code&gt;/fleet&lt;/code&gt; to parallelize, &lt;code&gt;/delegate&lt;/code&gt; to hand off, &lt;code&gt;/chronicle&lt;/code&gt; to review your session history.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Programmatic:&lt;/strong&gt; Pass a prompt directly with &lt;code&gt;copilot -p "your task here"&lt;/code&gt;. It runs, completes the task, exits. Good for scripts and automation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Native GitHub Integration via MCP
&lt;/h3&gt;

&lt;p&gt;Copilot CLI works directly with your issues and pull requests through GitHub's native MCP server. Search issues, analyze labels, create branches, open PRs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Custom Agents and Skills
&lt;/h3&gt;

&lt;p&gt;Use &lt;code&gt;AGENTS.md&lt;/code&gt; and Agent Skills to define custom instructions and tool access, so your agent works the same way every time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Copilot Coding Agent
&lt;/h2&gt;

&lt;p&gt;The coding agent is what I actually used to build the dreamchasers repo from my phone. It works autonomously in a GitHub Actions environment: you assign it an issue or describe a task, it explores your repo, writes the code, runs your tests and linters, and opens a pull request. You review it like any other PR.&lt;/p&gt;

&lt;p&gt;Copilot coding agent is available with GitHub Copilot Pro, Pro+, Business, and Enterprise plans.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Repo
&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%2F3s5hvo32fcm2a6iwr1p0.gif" 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%2F3s5hvo32fcm2a6iwr1p0.gif" alt="dreamchasers ASCII art" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/AndreaGriffiths11/dreamchasers" rel="noopener noreferrer"&gt;dreamchasers&lt;/a&gt;. Six tracks plus a bonus, album format — from making your first repo to contributing to open source. Everything runs in the browser.&lt;/p&gt;

&lt;h2&gt;
  
  
  Want to Try Copilot CLI?
&lt;/h2&gt;

&lt;p&gt;This is the tool that built the repo. It turns plain English into code, right from your terminal.&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;# Install Copilot CLI&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @github/copilot

&lt;span class="c"&gt;# Launch it&lt;/span&gt;
copilot
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Included in all Copilot plans, including Free. All you need is a GitHub account.&lt;/p&gt;

&lt;p&gt;If you want to go deeper, here's the &lt;a href="https://github.blog/ai-and-ml/github-copilot/github-copilot-cli-how-to-get-started/" rel="noopener noreferrer"&gt;official guide I wrote for the GitHub Blog&lt;/a&gt; and the &lt;a href="https://docs.github.com/en/copilot/concepts/agents/copilot-cli/about-copilot-cli" rel="noopener noreferrer"&gt;full documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Point
&lt;/h2&gt;

&lt;p&gt;Meek Mill getting into GitHub matters because someone who grew up on Dreams and Nightmares might see this and realize the tools are free, the community is open, and nobody is checking credentials at the door.&lt;/p&gt;

&lt;p&gt;Dream chasers ship code. 🎤&lt;/p&gt;

</description>
      <category>githubcopilot</category>
      <category>copilotcli</category>
      <category>copilotcodingagent</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Quantum Computing: The Compute Power Behind 'Curing Cancer'</title>
      <dc:creator>Andrea Liliana Griffiths</dc:creator>
      <pubDate>Tue, 24 Mar 2026 14:45:09 +0000</pubDate>
      <link>https://dev.to/andreagriffiths11/quantum-computing-the-compute-power-behind-curing-cancer-l87</link>
      <guid>https://dev.to/andreagriffiths11/quantum-computing-the-compute-power-behind-curing-cancer-l87</guid>
      <description>&lt;h1&gt;
  
  
  Quantum Computing: The Compute Power Behind "Curing Cancer"
&lt;/h1&gt;

&lt;p&gt;A few weeks ago, my boss Cassidy posted &lt;a href="https://youtu.be/FC7YGG0FzZ0" rel="noopener noreferrer"&gt;a video about her feelings on AI&lt;/a&gt;. She called it "An attempt at a balanced perspective on AI" and described the process as repeatedly "crashing out" while working through her thoughts.&lt;/p&gt;

&lt;p&gt;I watched it. Then I left a comment: "Let's get AI to cure cancer first, then throw it in the ocean."&lt;/p&gt;

&lt;p&gt;I'm a breast cancer survivor. That experience rewrites your priorities. When people ask what I want from AI, I don't say better autocomplete. I say cure cancer. Then throw it in the ocean. But cure cancer first.&lt;/p&gt;

&lt;p&gt;That comment stuck with me. I started wondering what it would actually take. Not the hype. Not the TED talks. The actual compute. And that question led me somewhere unexpected: quantum computing.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Quantum Computing Actually Is
&lt;/h2&gt;

&lt;p&gt;Let's clear something up. Quantum computers are not faster regular computers. They're fundamentally different machines that solve fundamentally different problems.&lt;/p&gt;

&lt;p&gt;Classical computers use bits. Each bit is either 0 or 1. You know this. It's how every computer you've ever used works.&lt;/p&gt;

&lt;p&gt;Quantum computers use qubits. A qubit can be 0, 1, or both at the same time through a property called superposition. When qubits interact through entanglement, they can represent and process vastly more information than the same number of classical bits. The math gets weird fast. But the intuition matters: quantum computers don't try every possibility sequentially. They explore probability spaces in ways that classical computers physically cannot replicate.&lt;/p&gt;

&lt;p&gt;This isn't theoretical anymore. &lt;a href="https://quantumai.google/" rel="noopener noreferrer"&gt;Google's Willow chip&lt;/a&gt; demonstrated a 13,000x speedup over the world's fastest supercomputer in October 2025 for a specific quantum algorithm. That's not a rounding error. That's a different category of computation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where We Are in 2026
&lt;/h2&gt;

&lt;p&gt;The quantum computing narrative has shifted from "maybe someday" to "which modality wins."&lt;/p&gt;

&lt;h3&gt;
  
  
  Caltech's 6,100-Qubit Array
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.caltech.edu/about/news/caltech-team-sets-record-with-6100-qubit-array" rel="noopener noreferrer"&gt;Caltech built a neutral-atom array with 6,100 qubits&lt;/a&gt; in September 2025, the largest controlled quantum system ever assembled. The previous record was around a thousand. These qubits maintained coherence for 13 seconds with 99.98% fidelity. Coherence time matters because it determines how much useful computation you can do before quantum effects collapse.&lt;/p&gt;

&lt;h3&gt;
  
  
  IBM's Nighthawk Processor
&lt;/h3&gt;

&lt;p&gt;Running at 120 qubits, &lt;a href="https://www.helpnetsecurity.com/2025/11/12/ibm-quantum-nighthawk-processor/" rel="noopener noreferrer"&gt;achieved a 10x speedup in quantum error correction decoding&lt;/a&gt;. Error correction is the bottleneck. Quantum states are fragile and every interaction with the environment introduces noise. IBM's progress means we're getting better at keeping quantum information intact long enough to compute with it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Quantinuum's H2 Processor
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.quantinuum.com/press-releases/quantinuum-and-microsoft-announce-new-era-in-quantum-computing-with-breakthrough-demonstration-of-reliable-qubits" rel="noopener noreferrer"&gt;Became the first quantum computer to reach Microsoft's Level 2 Resilient phase&lt;/a&gt;. They produced logical qubits with error rates 800x lower than physical rates using just 30 physical qubits to create four logical qubits.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Industry Crossed a Billion Dollars in Revenue
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://quantumcomputingreport.com/ionq-reports-on-its-q3-2025-financial-results-world-record-fidelity-achieved-and-record-cash-position/" rel="noopener noreferrer"&gt;IonQ&lt;/a&gt;, the largest publicly traded pure-play quantum company, hit $39.9M in Q3 2025 revenue, up 221% year-over-year. Governments have committed over $40 billion in national quantum strategies. These are not vaporware numbers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Drug Discovery Changes Everything
&lt;/h2&gt;

&lt;p&gt;Here's where cancer comes in.&lt;/p&gt;

&lt;p&gt;The pharmaceutical industry has a problem: most AI-designed drug molecules look promising on computers but are nearly impossible to synthesize in labs. This is called downstream attrition. You find a candidate that should work, spend millions developing it, then discover it can't actually be manufactured.&lt;/p&gt;

&lt;p&gt;Classical computers struggle with molecular simulation because the math of quantum mechanics scales exponentially with the number of electrons. Simulating a single caffeine molecule accurately requires classical computing resources that push against the limits of what's physically possible.&lt;/p&gt;

&lt;p&gt;Quantum computers are naturally suited for this. They don't simulate quantum mechanics. They &lt;em&gt;are&lt;/em&gt; quantum mechanics.&lt;/p&gt;

&lt;p&gt;In January 2026, &lt;a href="https://thequantuminsider.com/2026/01/12/researchers-report-quantum-computing-can-accelerate-drug-design/" rel="noopener noreferrer"&gt;PolarisQB released a head-to-head study&lt;/a&gt; showing their quantum annealing platform running on D-Wave hardware outperformed classical generative AI for drug discovery. Classical AI took 40 hours to suggest molecules. The quantum system took 30 minutes. More importantly, the quantum-generated leads were significantly easier to synthesize in the lab.&lt;/p&gt;

&lt;p&gt;In February 2026, &lt;a href="https://www.hpcwire.com/off-the-wire/telefonica-vithas-and-ufv-launch-quantum-computing-project-for-cancer-drug-design/" rel="noopener noreferrer"&gt;Telefónica, Vithas hospitals, and Francisco de Vitoria University launched a quantum computing project&lt;/a&gt; specifically for cancer drug design. They're targeting the BRAF V600E mutation, an altered protein that drives uncontrolled cancer cell growth. The goal is to use quantum algorithms to generate molecules that inhibit this protein. This is not a whitepaper. It's happening now.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Compute Requirements
&lt;/h2&gt;

&lt;p&gt;I asked: what would it actually take to cure cancer with compute?&lt;/p&gt;

&lt;p&gt;The honest answer is we don't know yet. But we're getting real data points.&lt;/p&gt;

&lt;p&gt;The number of possible drug-like molecules exceeds 10^60. That's more than atoms in the observable universe. Classical computers cannot search this space exhaustively, so they use heuristics, approximations, and machine learning to guess at promising regions. Quantum computers approach this differently. For specific optimization problems, and drug discovery is fundamentally an optimization problem, they can explore solution spaces in ways classical algorithms cannot match.&lt;/p&gt;

&lt;p&gt;Researchers at Caltech published a quantum computing framework in February 2026 specifically for multi-stage drug discovery, covering allosteric site identification, protein-peptide docking, and molecular dynamics. It encodes three quantum algorithms that classical methods struggle to approximate.&lt;/p&gt;

&lt;p&gt;The scale needed for practical advantage keeps shrinking. Google's demonstration used their 105-qubit Willow chip. IBM's roadmap targets 200 logical qubits by 2028. Logical qubits are error-corrected qubits that can run reliable computations. Each logical qubit requires many physical qubits to maintain, but the ratios are improving fast.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Hardware Reality
&lt;/h2&gt;

&lt;p&gt;Different companies are betting on different qubit technologies, and none have clearly won.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Superconducting Qubits (IBM, Google, Rigetti)&lt;/strong&gt;&lt;br&gt;
Offer fast gate operations but require millikelvin temperatures. IBM operates the largest cloud-accessible quantum fleet and Google achieved the landmark quantum advantage demonstration with this approach.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Trapped Ions (IonQ, Quantinuum)&lt;/strong&gt;&lt;br&gt;
Offer higher fidelity and fully connected qubits at the cost of slower operations. IonQ holds the world record at 99.99% two-qubit gate fidelity and Quantinuum's H2 processor leads in quantum volume.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Neutral Atoms (QuEra, Pasqal, Atom Computing)&lt;/strong&gt;&lt;br&gt;
Can pack thousands of qubits in arrays with longer coherence times. This is the technology behind Caltech's 6,100-qubit breakthrough.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Photonic Computing (PsiQuantum, Xanadu)&lt;/strong&gt;&lt;br&gt;
Has room temperature operation potential but harder gate reliability. PsiQuantum raised over $2 billion and is building datacenter-scale quantum compute centers.&lt;/p&gt;

&lt;p&gt;All of these are viable for different applications. The race is still open.&lt;/p&gt;

&lt;h2&gt;
  
  
  A New Research Agenda
&lt;/h2&gt;

&lt;p&gt;I started this with a frustrated comment about AI hype. I ended it with a reading list of quantum physics papers and a new appreciation for how much work happens between the hype cycles.&lt;/p&gt;

&lt;p&gt;The quantum computing industry has moved from "trust us, it's coming" to "here are the benchmarks." The applications have narrowed from "everything" to specific domains where quantum mechanics gives inherent advantages. Drug discovery and materials science lead that list.&lt;/p&gt;

&lt;p&gt;Cancer isn't one disease. It's thousands of molecular malfunctions, each requiring an understanding of specific protein interactions, cellular pathways, and drug binding mechanisms. Classical compute hits walls. Quantum compute might help us climb over them.&lt;/p&gt;

&lt;p&gt;I'm not saying quantum computers will cure cancer. I'm saying the people who might cure cancer are starting to use them. That's not AI hype. That's a research direction worth following.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Andrea Griffiths is a Senior Developer Advocate at GitHub and a breast cancer survivor. She writes &lt;a href="https://mainbranch.dev" rel="noopener noreferrer"&gt;Main Branch&lt;/a&gt;, a newsletter about developer fundamentals.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.caltech.edu/about/news/caltech-team-sets-record-with-6100-qubit-array" rel="noopener noreferrer"&gt;Caltech's 6,100-Qubit Array Announcement&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.hpcwire.com/off-the-wire/telefonica-vithas-and-ufv-launch-quantum-computing-project-for-cancer-drug-design/" rel="noopener noreferrer"&gt;Telefónica/Vithas Quantum Cancer Drug Project&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://quantumai.google/" rel="noopener noreferrer"&gt;Google Quantum AI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://quantumzeitgeist.com/quantum-computing-companies-in-2026-2/" rel="noopener noreferrer"&gt;Quantum Computing Companies in 2026&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>quantumcomputing</category>
      <category>drugdiscovery</category>
      <category>cancerresearch</category>
      <category>googlewillow</category>
    </item>
  </channel>
</rss>
