<?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: Wahib EL KHADIRI</title>
    <description>The latest articles on DEV Community by Wahib EL KHADIRI (@wahib_el_khadiri_0).</description>
    <link>https://dev.to/wahib_el_khadiri_0</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%2F4040823%2Fdc1c7aa7-603d-4f87-a82b-07c20c473251.png</url>
      <title>DEV Community: Wahib EL KHADIRI</title>
      <link>https://dev.to/wahib_el_khadiri_0</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/wahib_el_khadiri_0"/>
    <language>en</language>
    <item>
      <title>Coding with an AI agent: what actually changed (and what didnt)</title>
      <dc:creator>Wahib EL KHADIRI</dc:creator>
      <pubDate>Wed, 05 Aug 2026 07:49:51 +0000</pubDate>
      <link>https://dev.to/wahib_el_khadiri_0/coding-with-an-ai-agent-what-actually-changed-and-what-didnt-4a1m</link>
      <guid>https://dev.to/wahib_el_khadiri_0/coding-with-an-ai-agent-what-actually-changed-and-what-didnt-4a1m</guid>
      <description>&lt;p&gt;Every job post now says "we expect you to use AI in your daily workflow." Good — because used well, an AI coding agent is a real multiplier. Used badly, it's a confident intern that ships bugs. After months of building and shipping merged open-source PRs with an agent in the loop, here's what actually changed — and what didn't.&lt;/p&gt;

&lt;h2&gt;
  
  
  What genuinely got faster
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Navigating unfamiliar codebases.&lt;/strong&gt; Dropping into a repo I've never seen and asking "where is X handled and why" collapses hours into minutes. This is the single biggest win — not writing code, but &lt;em&gt;understanding&lt;/em&gt; it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Boilerplate and tests.&lt;/strong&gt; Regression tests, argument parsing, config plumbing — the stuff you know how to write but don't want to. The agent drafts, I review.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Refactors with a spec.&lt;/strong&gt; "Replace this nested loop with a vectorized construction, preserve ordering and the guards" → a clean patch I then &lt;em&gt;verify&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What did NOT change (and never should)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;You still own correctness.&lt;/strong&gt; I don't merge anything I can't explain and haven't tested. On one fix I had the agent generate a change, then I ran the old and new code side-by-side across every input and asserted identical output before opening the PR. The agent wrote the diff; &lt;em&gt;I&lt;/em&gt; signed off on it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Judgment is still yours.&lt;/strong&gt; Which issue to pick, whether the scope is sane, whether a bounty is a dead race — the agent will happily execute a bad plan. Deciding &lt;em&gt;what&lt;/em&gt; to do is the human's job.&lt;/p&gt;

&lt;h2&gt;
  
  
  The workflow that works for me
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Human:&lt;/strong&gt; pick a small, concrete problem.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Agent:&lt;/strong&gt; explore the codebase, propose a minimal change.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Human:&lt;/strong&gt; sanity-check the plan (reject vague or oversized ones).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Agent:&lt;/strong&gt; implement + draft a test.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Human:&lt;/strong&gt; run the full suite, verify, read every line.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Human:&lt;/strong&gt; write the PR, disclose AI assistance, ship.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Notice the human is at both ends. The agent compresses the middle.&lt;/p&gt;

&lt;h2&gt;
  
  
  The honest failure mode
&lt;/h2&gt;

&lt;p&gt;The trap is &lt;em&gt;trusting output you didn't verify&lt;/em&gt;. An agent will produce plausible, well-formatted, wrong code — and it looks exactly like the right code. The discipline that matters in 2026 isn't prompting; it's &lt;strong&gt;verification&lt;/strong&gt;. Reviewing AI output is now a core engineering skill, not an optional one.&lt;/p&gt;

&lt;p&gt;Delegation, not abdication. Let the agent do the typing. Keep the thinking.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>programming</category>
      <category>career</category>
    </item>
    <item>
      <title>How a self-taught dev gets merged PRs into real open-source projects</title>
      <dc:creator>Wahib EL KHADIRI</dc:creator>
      <pubDate>Wed, 05 Aug 2026 07:49:50 +0000</pubDate>
      <link>https://dev.to/wahib_el_khadiri_0/how-a-self-taught-dev-gets-merged-prs-into-real-open-source-projects-24g0</link>
      <guid>https://dev.to/wahib_el_khadiri_0/how-a-self-taught-dev-gets-merged-prs-into-real-open-source-projects-24g0</guid>
      <description>&lt;p&gt;I'm self-taught, 22, and I have merged pull requests in real open-source projects — a quantum-computing library, an AI coding-agent toolkit, security tooling, data stacks. No CS degree, no referral. Just a repeatable process. Here it is, no fluff.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why bother (if you're job-hunting)
&lt;/h2&gt;

&lt;p&gt;A merged PR is &lt;strong&gt;public, verifiable proof&lt;/strong&gt; you can read a real codebase, follow its conventions, and ship. It beats a wall of tutorial projects on a resume, because a stranger with commit rights already said &lt;em&gt;yes&lt;/em&gt; to your code.&lt;/p&gt;

&lt;h2&gt;
  
  
  The playbook
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Find a genuinely small, unclaimed issue
&lt;/h3&gt;

&lt;p&gt;Search GitHub for &lt;code&gt;label:"good first issue" state:open&lt;/code&gt; in a language you know. Then filter hard:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;0 comments&lt;/strong&gt; and &lt;strong&gt;no assignee&lt;/strong&gt; → nobody's racing you.&lt;/li&gt;
&lt;li&gt;The issue names the file and the fix → scope is bounded.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Skip anything vague ("improve testing", "add feature X"). Vague = subjective review = rejection.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# GitHub search that surfaces fresh, unclaimed issues
is:issue is:open label:"good first issue" no:assignee sort:created-desc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Check for competing PRs &lt;em&gt;before&lt;/em&gt; you start
&lt;/h3&gt;

&lt;p&gt;Fast-moving repos get duplicate PRs. If someone opened one an hour ago, move on — I've lost that race twice and learned.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Reproduce, fix, and &lt;strong&gt;add a test&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Clone, reproduce the bug, make the minimal change, then write a regression test. The test is what turns "trust me" into "here's proof." Run the full suite and note any failures that are pre-existing (verify with &lt;code&gt;git stash&lt;/code&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Match the house style
&lt;/h3&gt;

&lt;p&gt;Read &lt;code&gt;CONTRIBUTING.md&lt;/code&gt;. Some repos require you to comment "I'll take this" first. Some enforce DCO (&lt;code&gt;git commit -s&lt;/code&gt;). Some use Conventional Commits. Follow their rules exactly — reviewers notice.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Write the PR like a reviewer is busy
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;One sentence: what was broken.&lt;/li&gt;
&lt;li&gt;The fix, and &lt;em&gt;why&lt;/em&gt; this one.&lt;/li&gt;
&lt;li&gt;Proof it works (test output).&lt;/li&gt;
&lt;li&gt;Disclose AI assistance if you used it — honesty builds trust.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What I stopped doing
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Chasing bounties.&lt;/strong&gt; Most are dead (archived repos) or 200-person races. Terrible expected value.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Padding volume.&lt;/strong&gt; Two clean PRs to reputable repos beat ten to 3-star toy projects. Quality is the signal.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The mindset
&lt;/h2&gt;

&lt;p&gt;You're not "contributing to open source." You're solving one small, concrete problem for someone, cleanly, with a test. Do that ten times and you have a track record no bootcamp certificate can match.&lt;/p&gt;

&lt;p&gt;Start today: find one 0-comment &lt;code&gt;good first issue&lt;/code&gt;, and ship the smallest correct fix you can.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>career</category>
      <category>beginners</category>
      <category>productivity</category>
    </item>
    <item>
      <title>A GitHub Actions tag is a promise, not a fact: pinning by SHA the right way</title>
      <dc:creator>Wahib EL KHADIRI</dc:creator>
      <pubDate>Sun, 02 Aug 2026 22:58:53 +0000</pubDate>
      <link>https://dev.to/wahib_el_khadiri_0/a-github-actions-tag-is-a-promise-not-a-fact-pinning-by-sha-the-right-way-3np</link>
      <guid>https://dev.to/wahib_el_khadiri_0/a-github-actions-tag-is-a-promise-not-a-fact-pinning-by-sha-the-right-way-3np</guid>
      <description>&lt;p&gt;When you write &lt;code&gt;uses: actions/checkout@v4&lt;/code&gt; in a GitHub Actions workflow, you are not pinning anything. You are trusting a promise.&lt;/p&gt;

&lt;p&gt;A tag is a movable pointer. Whoever owns that repository can repoint &lt;code&gt;v4&lt;/code&gt; at a different commit tomorrow, after you reviewed it, and every run of your pipeline will silently pull the new code. In a job that holds a registry login, a PyPI token, or a signing key, that is exactly the place you do not want a mutable reference.&lt;/p&gt;

&lt;p&gt;I recently went through a project's workflows and pinned the remaining actions to commit SHAs. Here is what I actually learned doing it — beyond "just use the SHA".&lt;/p&gt;

&lt;h2&gt;
  
  
  A tag is a promise; a SHA is a fact
&lt;/h2&gt;

&lt;p&gt;Compare these two lines:&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;# a promise: "v4 will keep meaning what you reviewed"&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;docker/login-action@v4&lt;/span&gt;

&lt;span class="c1"&gt;# a fact: this exact tree, forever&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;docker/login-action@dbcb813823bdd20940b903addbd779551569679f&lt;/span&gt; &lt;span class="c1"&gt;# v4&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second form is content-addressed. &lt;code&gt;dbcb813…&lt;/code&gt; can only ever refer to one tree of code. If upstream is compromised and someone force-pushes &lt;code&gt;v4&lt;/code&gt; to a malicious commit, your pinned SHA keeps running the code you actually audited. That is the whole security argument for pinning, and it is a real one — tag-repointing has been used in real supply-chain incidents.&lt;/p&gt;

&lt;h2&gt;
  
  
  Re-resolve the SHAs yourself
&lt;/h2&gt;

&lt;p&gt;The interesting part is &lt;em&gt;how you get the SHA&lt;/em&gt;. It is tempting to copy it from a table someone handed you. Don't. The point of pinning is to pin to code &lt;strong&gt;you&lt;/strong&gt; verified, so resolve each ref yourself against the source of truth:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh api repos/docker/login-action/commits/v4 &lt;span class="nt"&gt;--jq&lt;/span&gt; .sha
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This dereferences the ref to the commit it currently points at. Do it for every action, and you have both verified the value and produced the exact string to paste. When I did this across seven &lt;code&gt;uses:&lt;/code&gt; lines, they matched the values I'd been given — but the trust now comes from having checked, not from having copied.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep the version comment, or you break Dependabot
&lt;/h2&gt;

&lt;p&gt;Here is the subtlety that turns a security win into a maintenance problem. Once you pin to a SHA, the human readability is gone — nobody knows &lt;code&gt;dbcb813&lt;/code&gt; is &lt;code&gt;v4&lt;/code&gt; at a glance, and neither does your update tooling &lt;strong&gt;unless you tell it&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="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;docker/login-action@dbcb813823bdd20940b903addbd779551569679f&lt;/span&gt; &lt;span class="c1"&gt;# v4&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dependabot parses that trailing &lt;code&gt;# v4&lt;/code&gt; comment. Keep it, and Dependabot keeps offering version bumps as PRs — you get the security of a pin &lt;em&gt;and&lt;/em&gt; a maintained update path. Drop the comment, and Dependabot goes quiet: your pin quietly rots, and a stale pin nobody notices is its own risk. The comment is not decoration; it is the contract with your update bot.&lt;/p&gt;

&lt;h2&gt;
  
  
  The one pin you have to think about
&lt;/h2&gt;

&lt;p&gt;Not every ref is a version tag. Some actions publish from a moving branch on purpose:&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;pypa/gh-action-pypi-publish@release/v1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;release/v1&lt;/code&gt; is a branch the maintainers push fixes to. Pinning it to a SHA is still correct — but now &lt;em&gt;you&lt;/em&gt; own the decision of when to move it forward, and this one holds the PyPI publish. That is a real trade: you have removed the silent-update risk, but you have taken on the duty to bump it deliberately when upstream ships a fix. Pin it, keep the &lt;code&gt;# release/v1&lt;/code&gt; comment so Dependabot still nudges you, and write down that you understand the trade. The judgement is the point, not the edit.&lt;/p&gt;

&lt;h2&gt;
  
  
  The takeaway
&lt;/h2&gt;

&lt;p&gt;Pinning actions by SHA is a one-line-per-&lt;code&gt;uses:&lt;/code&gt; change, and the diff looks trivial. The value isn't in the edit — it's in three habits:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Resolve every SHA yourself&lt;/strong&gt; against the upstream repo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep the &lt;code&gt;# vX&lt;/code&gt; comment&lt;/strong&gt; so Dependabot can still bump it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Name the moving-branch pins&lt;/strong&gt; and accept that you now own their updates.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A tag says "trust me." A SHA says "here is exactly what runs." In the job that holds your credentials, prefer the fact.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This came out of a real contribution — pinning the remaining actions across a project's workflows in &lt;a href="https://github.com/thingctx/thingctx/pull/127" rel="noopener noreferrer"&gt;thingctx#127&lt;/a&gt;. If you maintain workflows with credentialed jobs, it's an afternoon's audit worth doing.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>github</category>
      <category>devops</category>
      <category>cicd</category>
    </item>
    <item>
      <title>AgentOS: a Rust runtime for AI agents with deterministic time-travel replay</title>
      <dc:creator>Wahib EL KHADIRI</dc:creator>
      <pubDate>Sun, 26 Jul 2026 18:22:50 +0000</pubDate>
      <link>https://dev.to/wahib_el_khadiri_0/agentos-a-rust-runtime-for-ai-agents-with-deterministic-time-travel-replay-bmm</link>
      <guid>https://dev.to/wahib_el_khadiri_0/agentos-a-rust-runtime-for-ai-agents-with-deterministic-time-travel-replay-bmm</guid>
      <description>&lt;p&gt;Most agent frameworks help you &lt;em&gt;build&lt;/em&gt; a workflow. The harder part starts after that: the workflow has to run as a long-lived process, fail clearly, restart carefully, and be inspectable after the fact.&lt;/p&gt;

&lt;p&gt;That's the gap I'm building &lt;strong&gt;AgentOS&lt;/strong&gt; for — an open-source, Rust-first runtime layer that sits &lt;em&gt;underneath&lt;/em&gt; frameworks like LangGraph, AutoGen or CrewAI instead of replacing them.&lt;/p&gt;

&lt;h2&gt;
  
  
  What one process gives you
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cargo run &lt;span class="nt"&gt;-p&lt;/span&gt; agentos-cli &lt;span class="nt"&gt;--&lt;/span&gt; run &lt;span class="nt"&gt;--agent&lt;/span&gt; examples/simple_agent.toml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That single command brings up a supervised agent, a health endpoint, a gRPC message bus, a live SSE event stream, and a recorded trace you can replay later. No API key is needed just to bring the runtime up.&lt;/p&gt;

&lt;h2&gt;
  
  
  Time-travel debugging
&lt;/h2&gt;

&lt;p&gt;Your agent does something weird on step 7. Reproducing it costs real API calls, and it never behaves the same way twice.&lt;/p&gt;

&lt;p&gt;AgentOS journals every LLM exchange and tool result at the provider boundary, so any run can be replayed deterministically — and forked into alternate timelines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;agentOS run &lt;span class="nt"&gt;--agent&lt;/span&gt; my_agent.toml    &lt;span class="c"&gt;# every step journaled automatically&lt;/span&gt;
agentOS replay &lt;span class="nt"&gt;--session&lt;/span&gt; agent_123   &lt;span class="c"&gt;# offline re-run, no API cost, drift-checked&lt;/span&gt;
agentOS fork &lt;span class="nt"&gt;--from&lt;/span&gt; ckpt_4 &lt;span class="nt"&gt;--prompt&lt;/span&gt; &lt;span class="s2"&gt;"try the other path"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The dashboard's Recordings view turns those journals into a scrubbable timeline: step through the prompt, each exchange, tool calls and their results, with per-exchange checkpoints as fork anchors.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;crates/kernel&lt;/code&gt; — lifecycle, agent handles, supervisor&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;crates/bus&lt;/code&gt; — in-memory, gRPC, SSE and WebSocket messaging&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;crates/trace&lt;/code&gt; — recording, replay, diff, checkpoint model&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;crates/vault&lt;/code&gt; — secret isolation, encryption, scopes, audit&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;crates/memory&lt;/code&gt;, &lt;code&gt;crates/registry&lt;/code&gt;, &lt;code&gt;crates/llm&lt;/code&gt;, &lt;code&gt;crates/cli&lt;/code&gt;, &lt;code&gt;crates/sdk&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;dashboard/&lt;/code&gt; — React debugging surface&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Where it honestly stands
&lt;/h2&gt;

&lt;p&gt;Stable enough for local use: the &lt;code&gt;run / ps / logs / trace / replay&lt;/code&gt; CLI flows, local state inspection, export and import, and the core crates with workspace checks and tests.&lt;/p&gt;

&lt;p&gt;Still experimental: the dashboard, the WASM plugin runtime, Docker Compose packaging, LLM provider integrations, and Python/TypeScript SDK packaging. Stronger restart and recovery guarantees with explicit tests are next. It is an alpha, and I would rather say that than claim production hardening it has not earned yet.&lt;/p&gt;

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



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/WAHIB-EL-KHADIRI/AgentOS
&lt;span class="nb"&gt;cd &lt;/span&gt;AgentOS
cargo build &lt;span class="nt"&gt;--workspace&lt;/span&gt;
cargo run &lt;span class="nt"&gt;-p&lt;/span&gt; agentos-cli &lt;span class="nt"&gt;--&lt;/span&gt; run &lt;span class="nt"&gt;--agent&lt;/span&gt; examples/simple_agent.toml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Repo: &lt;a href="https://github.com/WAHIB-EL-KHADIRI/AgentOS" rel="noopener noreferrer"&gt;https://github.com/WAHIB-EL-KHADIRI/AgentOS&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Feedback on the runtime boundaries is what I want most: if you run agents today, what breaks first for you — supervision, observability, or reproducing failures?&lt;/p&gt;

</description>
      <category>rust</category>
      <category>ai</category>
      <category>opensource</category>
      <category>showdev</category>
    </item>
    <item>
      <title>I Taught an Open-Source SEO Tool to Check Whether Your Site Is Readable by AI Agents</title>
      <dc:creator>Wahib EL KHADIRI</dc:creator>
      <pubDate>Tue, 21 Jul 2026 23:08:35 +0000</pubDate>
      <link>https://dev.to/wahib_el_khadiri_0/i-taught-an-open-source-seo-tool-to-check-whether-your-site-is-readable-by-ai-agents-15i3</link>
      <guid>https://dev.to/wahib_el_khadiri_0/i-taught-an-open-source-seo-tool-to-check-whether-your-site-is-readable-by-ai-agents-15i3</guid>
      <description>&lt;p&gt;Most SEO audit tools still ask the questions search engines cared about ten years ago: is your title tag the right length, do your images have alt text, is your sitemap valid. Those still matter. But a growing chunk of how people find content now goes through an AI assistant instead of a search results page, and almost no audit tool checks whether your site is even &lt;em&gt;reachable&lt;/em&gt; by one.&lt;/p&gt;

&lt;p&gt;I picked up an open issue on &lt;a href="https://github.com/every-app/open-seo" rel="noopener noreferrer"&gt;open-seo&lt;/a&gt; (an open-source Semrush/Ahrefs alternative) to close that gap, and it turned into a good lesson in scoping a feature for someone else's codebase instead of your own.&lt;/p&gt;

&lt;h2&gt;
  
  
  The actual question
&lt;/h2&gt;

&lt;p&gt;"Is this site AI-readable?" breaks down into concrete, checkable things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Does &lt;code&gt;robots.txt&lt;/code&gt; block the crawlers that build AI search indexes and answer live user requests?&lt;/li&gt;
&lt;li&gt;Does the site have an &lt;code&gt;llms.txt&lt;/code&gt; — the emerging convention that gives an AI assistant a clean map of your important pages?&lt;/li&gt;
&lt;li&gt;Does the site advertise a Markdown alternate for its pages, so an assistant can read clean content instead of parsing full HTML?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Straightforward to state. The interesting part was not flagging noise.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lesson 1: not every robots.txt block is a signal
&lt;/h2&gt;

&lt;p&gt;A site with &lt;code&gt;Disallow: /&lt;/code&gt; for every crawler made a deliberate, site-wide choice. Reporting "GPTBot is blocked!" on a site that blocks &lt;em&gt;everything&lt;/em&gt; isn't useful information — it's noise dressed up as an insight. So the check only flags an AI agent when it's treated &lt;strong&gt;worse than the generic rules&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rootUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;origin&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;robots&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isAllowed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rootUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;GENERIC_PROBE_AGENT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt; &lt;span class="c1"&gt;// whole site is closed — not an AI-specific signal&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;I also grouped agents by &lt;em&gt;why they visit&lt;/em&gt; instead of firing one issue per bot. &lt;code&gt;GPTBot&lt;/code&gt; and &lt;code&gt;ClaudeBot&lt;/code&gt; are training crawlers; blocking them is often an intentional content policy and barely worth a heads-up. &lt;code&gt;ChatGPT-User&lt;/code&gt; and &lt;code&gt;Claude-User&lt;/code&gt; fetch a page live because an actual human asked an assistant about it right now — blocking those is a much bigger deal, because you're breaking a request in progress, not opting out of a training set. Same signal, completely different severity, so they're separate issue types with separate default severities instead of one generic "AI crawler blocked" bucket.&lt;/p&gt;
&lt;h2&gt;
  
  
  Lesson 2: absence isn't always an error
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;llms.txt&lt;/code&gt; and Markdown alternates are both new enough that almost nobody has them yet. If the check flagged every single audited site for "missing Markdown alternates," it would train users to ignore the audit tool's warnings entirely — the boy-who-cried-wolf failure mode of any linter. Both checks are &lt;code&gt;info&lt;/code&gt; severity with copy that says, explicitly, "this is common, not an error." The one genuinely broken state — a site that &lt;em&gt;serves&lt;/em&gt; &lt;code&gt;llms.txt&lt;/code&gt; but violates its one hard structural requirement (starts with an H1) — is the only case that gets bumped to &lt;code&gt;warning&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Lesson 3: match the codebase's own constraints, not your own instincts
&lt;/h2&gt;

&lt;p&gt;My first instinct for "does this page have a Markdown alternate" was to persist a new boolean column on the crawled-pages table. Then I actually looked at how the project's crawl pipeline works: full page data lives in a database table, but only a &lt;em&gt;slim summary&lt;/em&gt; (title, status code, a few other fields) survives between crawl phases as durable workflow state — link lists and everything else deliberately get dropped to keep memory bounded on 10,000-page crawls.&lt;/p&gt;

&lt;p&gt;Adding a persisted column meant a schema migration, which meant touching both the SQLite and Postgres schema paths this project supports side by side — a much bigger, riskier diff for a feature that doesn't actually need to survive past the audit run. So instead the flag rides through the same transient summary object the pipeline already carries between phases, and the &lt;em&gt;finding&lt;/em&gt; — not the raw per-page flag — is the only thing that gets persisted, as a single site-level issue row. Same pattern the project already used for the file-based &lt;code&gt;llms.txt&lt;/code&gt; check; I just extended it instead of inventing a new one.&lt;/p&gt;
&lt;h2&gt;
  
  
  Lesson 4: extend the open PR, don't fragment the review
&lt;/h2&gt;

&lt;p&gt;I'd already opened a PR for the robots.txt and &lt;code&gt;llms.txt&lt;/code&gt; checks. Before anyone had reviewed it, I built the Markdown-alternates check too — and instead of opening a third PR, I pushed a second commit onto the same branch. The maintainer hasn't looked at any of it yet, so there was no in-flight review to disrupt, and one PR that closes three-quarters of the original issue is easier to review than three PRs that each close a quarter of it and reference each other.&lt;/p&gt;
&lt;h2&gt;
  
  
  Result
&lt;/h2&gt;

&lt;p&gt;19 unit tests, no schema changes, no new external API calls beyond one extra fetch for &lt;code&gt;llms.txt&lt;/code&gt;. The PR's open here if you want to see the actual diff: &lt;a href="https://github.com/every-app/open-seo/pull/122" rel="noopener noreferrer"&gt;every-app/open-seo#122&lt;/a&gt;.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/every-app" rel="noopener noreferrer"&gt;
        every-app
      &lt;/a&gt; / &lt;a href="https://github.com/every-app/open-seo" rel="noopener noreferrer"&gt;
        open-seo
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Open source alternative to Semrush and Ahrefs
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;OpenSEO&lt;/h1&gt;
&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;Open source alternative to Semrush and Ahrefs&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;OpenSEO is an SEO tool for &lt;em&gt;the people&lt;/em&gt;. If tools like Semrush or Ahrefs are too expensive or bloated, OpenSEO is a pay-as-you-go alternative that you actually control.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;All-in-one SEO tool for you and your AI agent.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Connect with any agent like Claude Code, OpenClaw or Hermes. We have pre-built skills, but you can build your own to tailor OpenSEO to your needs.&lt;/p&gt;

&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://private-user-images.githubusercontent.com/44480372/601812447-fd208249-44ea-4849-bb4b-5fc896aeab73.png?jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3ODUwODQ1MTYsIm5iZiI6MTc4NTA4NDIxNiwicGF0aCI6Ii80NDQ4MDM3Mi82MDE4MTI0NDctZmQyMDgyNDktNDRlYS00ODQ5LWJiNGItNWZjODk2YWVhYjczLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNjA3MjYlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjYwNzI2VDE2NDMzNlomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWJhMTQxNzFmZDY1MGU2OGMwNTQ4M2NjNDk2MTM0OTliODQ1YmUwMTM0ZjVmZGNkZTkwNWYxNTBjM2EwNDcyYzAmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JnJlc3BvbnNlLWNvbnRlbnQtdHlwZT1pbWFnZSUyRnBuZyJ9.jDWVtMNTfUSVh4FckjfKPoxhTn2d1wOvLiQ2vNjfOw8"&gt;&lt;img width="1385" height="794" alt="Image" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fprivate-user-images.githubusercontent.com%2F44480372%2F601812447-fd208249-44ea-4849-bb4b-5fc896aeab73.png%3Fjwt%3DeyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3ODUwODQ1MTYsIm5iZiI6MTc4NTA4NDIxNiwicGF0aCI6Ii80NDQ4MDM3Mi82MDE4MTI0NDctZmQyMDgyNDktNDRlYS00ODQ5LWJiNGItNWZjODk2YWVhYjczLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNjA3MjYlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjYwNzI2VDE2NDMzNlomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWJhMTQxNzFmZDY1MGU2OGMwNTQ4M2NjNDk2MTM0OTliODQ1YmUwMTM0ZjVmZGNkZTkwNWYxNTBjM2EwNDcyYzAmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JnJlc3BvbnNlLWNvbnRlbnQtdHlwZT1pbWFnZSUyRnBuZyJ9.jDWVtMNTfUSVh4FckjfKPoxhTn2d1wOvLiQ2vNjfOw8" class="js-gh-image-fallback"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Hosted Version&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;Try OpenSEO for free on our website. If you want to support the project, a hosted subscription is $10/month.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://openseo.so" rel="nofollow noopener noreferrer"&gt;openseo.so&lt;/a&gt;&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Why use OpenSEO?&lt;/h2&gt;
&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Best in class MCP and AI Skills.&lt;/li&gt;
&lt;li&gt;Modern, simple UI.
&lt;ul&gt;
&lt;li&gt;Focused workflows instead of a bloated, complex SEO suite.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;No subscriptions.

&lt;ul&gt;
&lt;li&gt;Bring your own DataForSEO API key and pay only for what you use.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Fork and vibe code your own custom tool.&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Main SEO Workflows&lt;/h2&gt;

&lt;/div&gt;


&lt;ul&gt;

&lt;li&gt;Keyword research&lt;/li&gt;

&lt;li&gt;Rank tracking&lt;/li&gt;

&lt;li&gt;Competitor Insights&lt;/li&gt;

&lt;li&gt;Backlinks&lt;/li&gt;

&lt;li&gt;Site…&lt;/li&gt;

&lt;/ul&gt;&lt;/div&gt;
&lt;br&gt;
  &lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/every-app/open-seo" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;p&gt;The code itself was the easy part. The actual work was reading how someone else already solved similar problems in their codebase before writing a single line — the "how do I avoid noise" and "how do I fit this project's existing shape" questions mattered more than the crawler-detection logic itself.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>typescript</category>
      <category>webdev</category>
      <category>ai</category>
    </item>
    <item>
      <title>I Shipped My First Rust Release, and CI Turned Red Twice in 20 Minutes</title>
      <dc:creator>Wahib EL KHADIRI</dc:creator>
      <pubDate>Tue, 21 Jul 2026 22:43:39 +0000</pubDate>
      <link>https://dev.to/wahib_el_khadiri_0/i-shipped-my-first-rust-release-and-ci-turned-red-twice-in-20-minutes-31hp</link>
      <guid>https://dev.to/wahib_el_khadiri_0/i-shipped-my-first-rust-release-and-ci-turned-red-twice-in-20-minutes-31hp</guid>
      <description>&lt;p&gt;I shipped the first public release of my Rust project last night. Within about twenty minutes, CI turned red twice. Here's what broke, how I found it, and the two calls I made under a bit of time pressure.&lt;/p&gt;

&lt;h2&gt;
  
  
  The project
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/WAHIB-EL-KHADIRI/AgentOS" rel="noopener noreferrer"&gt;AgentOS&lt;/a&gt; is a runtime layer for AI agents — the infrastructure &lt;em&gt;around&lt;/em&gt; an agent, not the agent logic itself: supervised lifecycle, a gRPC message bus, a health endpoint, an SSE event stream, a secrets vault, and deterministic time-travel replay (every LLM/tool exchange gets journaled, so a run can be replayed offline with no API cost, and forked into alternate timelines from any checkpoint).&lt;/p&gt;

&lt;p&gt;It's a 10-crate Rust workspace, MIT/Apache-2.0. I'd been building it privately for a while. Last night I flipped the repo to public and tagged the first alpha release. That's when things got interesting.&lt;/p&gt;

&lt;h2&gt;
  
  
  Failure #1: a clippy lint that didn't exist last month
&lt;/h2&gt;

&lt;p&gt;The repo had been private, so CI hadn't run against a fresh &lt;code&gt;clippy&lt;/code&gt; in a while. The moment I pushed a commit after going public, this showed up:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;you&lt;/span&gt; &lt;span class="n"&gt;seem&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;want&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;iterate&lt;/span&gt; &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="nv"&gt;'s&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt;
   &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;crates&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;bus&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;grpc&lt;/span&gt;&lt;span class="py"&gt;.rs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;631&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;37&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt;
&lt;span class="mi"&gt;631&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;         &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_agent_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;senders&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;subs&lt;/span&gt;&lt;span class="nf"&gt;.iter&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="o"&gt;^^^^^^^^^^^&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt;
    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;corresponding&lt;/span&gt; &lt;span class="n"&gt;method&lt;/span&gt;
&lt;span class="mi"&gt;631&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;         &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_agent_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;senders&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;subs&lt;/span&gt;&lt;span class="nf"&gt;.iter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="mi"&gt;631&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;         &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;senders&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;subs&lt;/span&gt;&lt;span class="nf"&gt;.values&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;clippy::for_kv_map&lt;/code&gt;, denied by &lt;code&gt;-D warnings&lt;/code&gt; in CI. Fair catch — the code was iterating a &lt;code&gt;HashMap&lt;/code&gt; and discarding the key on every iteration, which is exactly what &lt;code&gt;.values()&lt;/code&gt; is for. One-line fix:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// before&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_agent_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;senders&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;subs&lt;/span&gt;&lt;span class="nf"&gt;.iter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

&lt;span class="c1"&gt;// after&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;senders&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;subs&lt;/span&gt;&lt;span class="nf"&gt;.values&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;Pushed, CI green again. This one was boring, which is the best kind of bug to have.&lt;/p&gt;
&lt;h2&gt;
  
  
  Failure #2: the release matrix, at 12:33am
&lt;/h2&gt;

&lt;p&gt;The bigger one showed up when I tagged &lt;code&gt;v0.1.0-alpha&lt;/code&gt;. The release workflow builds five targets in parallel — Linux x64, Linux arm64, macOS Intel, macOS Apple Silicon, Windows — and packages each into a binary release with checksums.&lt;/p&gt;

&lt;p&gt;Four went green. Linux arm64 died with:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;error: failed to run custom build command for `openssl-sys v0.9.116`
...
Could not find directory of OpenSSL installation
$HOST = x86_64-unknown-linux-gnu
$TARGET = aarch64-unknown-linux-gnu
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;code&gt;openssl-sys&lt;/code&gt; needs a real OpenSSL installation (headers + libs) for the &lt;em&gt;target&lt;/em&gt; architecture to link against, and cross-compiling from an x86_64 GitHub Actions runner to arm64 doesn't have that available without extra setup. Not a code bug — a missing piece of cross-compilation infrastructure.&lt;/p&gt;

&lt;p&gt;I had three honest options at that point:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Block the whole release until arm64 cross-compiling was solved properly&lt;/li&gt;
&lt;li&gt;Vendor OpenSSL and wire up a cross-linker for the arm64 target under time pressure, late at night, for a release I hadn't tested that way before&lt;/li&gt;
&lt;li&gt;Ship the four targets that work, drop arm64 from &lt;em&gt;this&lt;/em&gt; release, and track the real fix as its own issue&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I went with option 3. Four platforms is still a real alpha release that covers the overwhelming majority of contributors trying it out. Blocking on a cross-compilation edge case for a Linux architecture almost nobody in the alpha audience runs felt like optimizing for the wrong thing at midnight. And silently vendoring a rushed fix into a security-relevant dependency (TLS) is exactly the kind of shortcut that comes back to bite you.&lt;/p&gt;

&lt;p&gt;So: pulled the target from the matrix, re-tagged, watched the four remaining builds go green, and &lt;a href="https://github.com/WAHIB-EL-KHADIRI/AgentOS/issues/38" rel="noopener noreferrer"&gt;filed the real fix as its own issue&lt;/a&gt; with three candidate approaches laid out (the best one is probably migrating off &lt;code&gt;openssl-sys&lt;/code&gt; to &lt;code&gt;rustls&lt;/code&gt; entirely, which would remove the system OpenSSL dependency for &lt;em&gt;every&lt;/em&gt; target, not just arm64 — cross-compilation problems like this are usually a sign the dependency choice needs revisiting, not just the CI config).&lt;/p&gt;
&lt;h2&gt;
  
  
  The one check I'm glad I ran before either of this
&lt;/h2&gt;

&lt;p&gt;Before any of the above, I'd actually run the README's own quickstart end to end — &lt;code&gt;cargo build --workspace&lt;/code&gt;, then run the example agent — specifically to catch the gap between "the README claims this works" and "this actually works." It did, and the real terminal output (supervisor spawning the agent, health server on &lt;code&gt;:8080&lt;/code&gt;, gRPC bus on &lt;code&gt;:50051&lt;/code&gt;, an SSE stream on &lt;code&gt;:8081&lt;/code&gt;) is now in the README instead of a hypothetical example. I also downloaded the actual released Windows binary afterward and ran &lt;code&gt;agentOS.exe --version&lt;/code&gt; against it — small thing, but it's the difference between "the release workflow exited 0" and "a stranger who downloads this file gets a working program."&lt;/p&gt;

&lt;p&gt;Neither bug was catastrophic. Both were the kind of thing that's mildly stressful in the moment and completely mundane in hindsight — which is most of what real engineering work actually looks like, release-day war stories included.&lt;/p&gt;

&lt;p&gt;If you want to poke at it, the repo's here: &lt;strong&gt;&lt;a href="https://github.com/WAHIB-EL-KHADIRI/AgentOS" rel="noopener noreferrer"&gt;github.com/WAHIB-EL-KHADIRI/AgentOS&lt;/a&gt;&lt;/strong&gt;. There are a handful of labeled &lt;code&gt;good first issue&lt;/code&gt;s if anyone wants to dig into a self-contained piece of it — I'm around to answer questions on any of them.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/WAHIB-EL-KHADIRI" rel="noopener noreferrer"&gt;
        WAHIB-EL-KHADIRI
      &lt;/a&gt; / &lt;a href="https://github.com/WAHIB-EL-KHADIRI/AgentOS" rel="noopener noreferrer"&gt;
        AgentOS
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Runtime infrastructure for AI agents — lifecycle, supervision, secrets, and deterministic time-travel replay. Built in Rust.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;AgentOS - Runtime Infrastructure for AI Agents&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;&lt;a href="https://www.rust-lang.org/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/5bfae72232b83a4d4178c88542d70400585d892a0daf6077c9f3f385b9293f82/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f527573742d312e39342532422d6f72616e6765" alt="Rust"&gt;&lt;/a&gt;
&lt;a href="https://github.com/WAHIB-EL-KHADIRI/AgentOS#license" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/19e546f568d501b01caf5f8c4e7116e2df532b762bb3d2de68ecf1f4f0b2e0c6/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d4d49542532304f522532304170616368652d2d322e302d626c7565" alt="License"&gt;&lt;/a&gt;
&lt;a href="https://github.com/WAHIB-EL-KHADIRI/agentOS/actions/workflows/ci.yml" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/WAHIB-EL-KHADIRI/agentOS/actions/workflows/ci.yml/badge.svg" alt="CI"&gt;&lt;/a&gt;
&lt;a href="https://github.com/WAHIB-EL-KHADIRI/AgentOS/scripts/check.ps1" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/60b7735e3302f07a0ee15ef29d63e76b806bf7d95b809274afe48625225df06b/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f77696e646f77732d737570706f727465642d626c7565" alt="Windows"&gt;&lt;/a&gt;
&lt;a href="https://github.com/WAHIB-EL-KHADIRI/AgentOS/docs/" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/7386e7990576f21a5320b5f4e5a0e54bc941305dd1498b29d8e8709bbb4d38dd/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f646f63732d617661696c61626c652d626c7565" alt="Docs"&gt;&lt;/a&gt;
&lt;a href="https://github.com/WAHIB-EL-KHADIRI/AgentOS#quick-start" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/97bf57002f6627adc71a5e403cee8fb6d67ac48676e7a46c841d919dc3d92723/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f696e7374616c6c2d6f6e652d2d6c696e65722d73756363657373" alt="Install"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;AgentOS is an open-source runtime layer for AI agents. It focuses on the
infrastructure around agents: lifecycle, supervision, messaging, state, secrets
observability, and trace replay.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Created by &lt;a href="https://github.com/WAHIB-EL-KHADIRI" rel="noopener noreferrer"&gt;WAHIB EL KHADIRI&lt;/a&gt;&lt;/strong&gt; — founder and architect.&lt;/p&gt;
&lt;p&gt;Most agent frameworks help you build an agent workflow. AgentOS focuses on what
happens after that workflow needs to run as a long-lived process, fail clearly
restart carefully, and be inspected after the fact.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;See it run&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;Real output from a fresh clone — no API key required to bring the runtime up:&lt;/p&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;
&lt;pre class="notranslate"&gt;&lt;code&gt;$ cargo run -p agentos-cli -- run --agent examples/simple_agent.toml
INFO agentos_kernel::supervisor: agent spawned and running agent_id=agent_simple_agent state=Running name=simple-agent
INFO agentos_kernel::agent: agent loop started agent_id=agent_simple_agent
INFO agentos_kernel::events: system event emitted event=agent.spawned seq=0
INFO agentOS::run: AgentOS runtime started agent_id=agent_simple_agent host=127.0.0.1 http_port=8080 grpc_port=50051 sse_port=8081
INFO agentos_kernel::health: health server listening on 127.0.0.1:8080
INFO agentos_bus::grpc: gRPC bus server listening on 127.0.0.1:50051&lt;/code&gt;&lt;/pre&gt;…&lt;/div&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/WAHIB-EL-KHADIRI/AgentOS" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


</description>
      <category>rust</category>
      <category>opensource</category>
      <category>showdev</category>
      <category>ai</category>
    </item>
  </channel>
</rss>
