<?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: Amir Saoudi</title>
    <description>The latest articles on DEV Community by Amir Saoudi (@amirdiaz).</description>
    <link>https://dev.to/amirdiaz</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%2F4157352%2F13d6162e-774a-441b-a6ab-d2579466f50a.png</url>
      <title>DEV Community: Amir Saoudi</title>
      <link>https://dev.to/amirdiaz</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/amirdiaz"/>
    <language>en</language>
    <item>
      <title>I track a public data registry from my terminal now — zero dependencies, one file</title>
      <dc:creator>Amir Saoudi</dc:creator>
      <pubDate>Fri, 02 Oct 2026 20:01:34 +0000</pubDate>
      <link>https://dev.to/amirdiaz/i-track-a-public-data-registry-from-my-terminal-now-zero-dependencies-one-file-3h1a</link>
      <guid>https://dev.to/amirdiaz/i-track-a-public-data-registry-from-my-terminal-now-zero-dependencies-one-file-3h1a</guid>
      <description>&lt;p&gt;I use a lot of open data registries, and they all share one annoying property: you find&lt;br&gt;
out something changed &lt;em&gt;after&lt;/em&gt; it matters. A vendor gets added overnight, a grade shifts,&lt;br&gt;
an offer disappears — and my notes are silently stale.&lt;/p&gt;

&lt;p&gt;So I built a tiny tracker for one of them, and it turned out to be simpler than I&lt;br&gt;
expected. The whole thing is a single Python file with zero dependencies — no pip&lt;br&gt;
install, no virtualenv, no API key. I want to walk through the pattern because it&lt;br&gt;
generalizes to any registry that publishes JSON.&lt;/p&gt;
&lt;h2&gt;
  
  
  The registry
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://sourcey.computer" rel="noopener noreferrer"&gt;Sourcey&lt;/a&gt; publishes three public datasets as plain JSON plus&lt;br&gt;
a release feed: a companies registry (543 companies when I last checked), startup&lt;br&gt;
credits, and an agent-readiness table with letter grades. On 2026-10-02 the live&lt;br&gt;
release reported &lt;code&gt;sha256:8094c042&lt;/code&gt; consistently across all three datasets — that's&lt;br&gt;
the number that makes verification possible.&lt;/p&gt;

&lt;p&gt;The key detail: every dataset snapshot is addressable and the current release carries&lt;br&gt;
a digest. That's all you need for real change detection — not "fetch and eyeball" but&lt;br&gt;
"prove the bytes changed."&lt;/p&gt;
&lt;h2&gt;
  
  
  The tool
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/AmirDiaz/sourcey-tracker" rel="noopener noreferrer"&gt;sourcey-tracker&lt;/a&gt; — one file, ~450 lines,&lt;br&gt;
stdlib only. It gives you five commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;python3 tracker.py status          &lt;span class="c"&gt;# release, digest, entity counts&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;python3 tracker.py snapshot        &lt;span class="c"&gt;# immutable local snapshot with digest&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;python3 tracker.py verify         &lt;span class="c"&gt;# re-hash the snapshot (detects tampering)&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;python3 tracker.py diff snap1 snap2   &lt;span class="c"&gt;# field-level changes between releases&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;python3 tracker.py changelog snap1 snap2
&lt;span class="nv"&gt;$ &lt;/span&gt;python3 tracker.py watch &lt;span class="nt"&gt;--once&lt;/span&gt;   &lt;span class="c"&gt;# CI-friendly: exit 1 if anything changed&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;status&lt;/code&gt; gives you the dated-fact view of the registry — release id, when it was cut,&lt;br&gt;
and the entity counts per dataset. &lt;code&gt;diff&lt;/code&gt; is the interesting one: it walks both&lt;br&gt;
snapshots and reports added entities, field-level changes, and removals with old and&lt;br&gt;
new values. When I mutation-tested it — adding a fake company, changing one grade from&lt;br&gt;
A to F, deleting an offer — it caught all three.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why zero dependencies is a feature, not a flex
&lt;/h2&gt;

&lt;p&gt;Every dependency is a supply-chain vote you cast on behalf of everyone who runs your&lt;br&gt;
tool. &lt;code&gt;urllib.request&lt;/code&gt; has been in the stdlib since Python 2.something, &lt;code&gt;hashlib&lt;/code&gt;&lt;br&gt;
ships with SHA-256 built in, and &lt;code&gt;json&lt;/code&gt; is right there. For a read-only tracker the&lt;br&gt;
web platform of 2008 is genuinely enough.&lt;/p&gt;

&lt;p&gt;The practical payoff: anyone can audit the whole attack surface in one sitting. A&lt;br&gt;
reader can verify the tool isn't exfiltrating anything by reading one file — no&lt;br&gt;
&lt;code&gt;pip-audit&lt;/code&gt; ritual, no lockfile archaeology. For security tooling that's not a nice&lt;br&gt;
to have, it's the whole point.&lt;/p&gt;

&lt;p&gt;I've been applying the same discipline to the rest of the mini-toolchain:&lt;br&gt;
&lt;a href="https://github.com/AmirDiaz/sourcey-registry-cli" rel="noopener noreferrer"&gt;sourcey-registry-cli&lt;/a&gt; queries the&lt;br&gt;
datasets from the command line,&lt;br&gt;
&lt;a href="https://github.com/AmirDiaz/readiness-badges" rel="noopener noreferrer"&gt;readiness-badges&lt;/a&gt; renders the grades as&lt;br&gt;
SVG badges, &lt;a href="https://github.com/AmirDiaz/x402-balance" rel="noopener noreferrer"&gt;x402-balance&lt;/a&gt; watches a wallet&lt;br&gt;
for USDC arriving on Base via a raw JSON-RPC &lt;code&gt;eth_call&lt;/code&gt;, and&lt;br&gt;
&lt;a href="https://github.com/AmirDiaz/franticls" rel="noopener noreferrer"&gt;franticls&lt;/a&gt; scans a public bounty board with&lt;br&gt;
price and claim-slot pressure. One file each, stdlib only, MIT licensed.&lt;/p&gt;

&lt;h2&gt;
  
  
  The verification pattern
&lt;/h2&gt;

&lt;p&gt;The part I'd actually copy into other projects is the snapshot/verify split:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;snapshot&lt;/code&gt; writes &lt;code&gt;{data, meta: {source, release_id, sha256, taken_at}}&lt;/code&gt; and prints
the digest.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;verify&lt;/code&gt; re-reads the file, re-computes the digest over the &lt;em&gt;canonical JSON&lt;/em&gt;
serialization, and compares.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;diff&lt;/code&gt; compares two snapshots &lt;strong&gt;by digest first&lt;/strong&gt; — identical digests short-circuit
to "no changes" without walking the data.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Canonical serialization (sorted keys, fixed separators) matters more than people&lt;br&gt;
think. If you hash &lt;code&gt;json.dumps(obj)&lt;/code&gt; with default settings you'll get false diffs from&lt;br&gt;
key ordering alone.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I learned mutation-testing my own diff
&lt;/h2&gt;

&lt;p&gt;I didn't trust &lt;code&gt;diff&lt;/code&gt; until I broke it on purpose:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Added entity&lt;/strong&gt; — new key in the companies map → reported under &lt;code&gt;added&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Changed field&lt;/strong&gt; — one company's &lt;code&gt;region: "EU"&lt;/code&gt; → &lt;code&gt;"US"&lt;/code&gt; → old and new values printed&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Removed entity&lt;/strong&gt; — deleted offer → reported under &lt;code&gt;removed&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Grade change&lt;/strong&gt; — &lt;code&gt;A&lt;/code&gt; → &lt;code&gt;F&lt;/code&gt; → surfaced with the entity name and field path&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The failure mode that surprised me: my first version compared entity &lt;em&gt;sets&lt;/em&gt; but not&lt;br&gt;
field values, so a grade change produced no output at all. The lesson — for a tracker,&lt;br&gt;
"same entities" and "same data" are different claims, and you have to test both.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use it on other registries
&lt;/h2&gt;

&lt;p&gt;The pattern is deliberately registry-agnostic: fetch JSON → canonicalize → digest →&lt;br&gt;
snapshot → diff. If a registry you care about publishes versioned JSON (and more of&lt;br&gt;
them do, because agents need stable URLs to cite), you can point this shape at it in&lt;br&gt;
an afternoon. The only registry-specific code in the tool is the endpoint table at&lt;br&gt;
the top of the file.&lt;/p&gt;

&lt;p&gt;Go break something on purpose first though. A tracker you haven't mutation-tested is&lt;br&gt;
just a vibes engine.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;All tools referenced are MIT licensed and single-file. If you track a public&lt;br&gt;
registry with something better, I genuinely want to see it — the whole point of&lt;br&gt;
doing this in the open.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>cli</category>
      <category>data</category>
      <category>programming</category>
      <category>python</category>
    </item>
    <item>
      <title>Five checks before you let an AI agent open a SaaS account on its own</title>
      <dc:creator>Amir Saoudi</dc:creator>
      <pubDate>Fri, 02 Oct 2026 12:03:48 +0000</pubDate>
      <link>https://dev.to/amirdiaz/five-checks-before-you-let-an-ai-agent-open-a-saas-account-on-its-own-c6b</link>
      <guid>https://dev.to/amirdiaz/five-checks-before-you-let-an-ai-agent-open-a-saas-account-on-its-own-c6b</guid>
      <description>&lt;p&gt;I run a small automation setup where agents handle repetitive SaaS work for me. They sign up for trials, provision API keys, and sometimes pay for a plan when a task needs a real account. After enough failures, I started auditing services before handing them over, and I wrote down the checks I run now. They have saved me a lot of dead ends, and they might save you some too.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;First, machine credentials.&lt;/strong&gt; A service can claim developer friendliness and still force you through a human-only gate. Password-based login with no API keys, or keys that only appear after a sales call, mean the agent stops at the door. I look for documented key issuance, OAuth flows that do not require a browser handoff, and tokens I can rotate from the CLI. If the signup form quietly requires a phone number for SMS verification, that is usually the end of the line for an unattended agent, and I move on.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Second, pricing that a machine can read.&lt;/strong&gt; You would be surprised how many services hide their real pricing behind a contact form. If a page cannot tell me, in plain fetchable HTML, what a plan costs, what the limits are, and whether it recurs monthly, my agent cannot make a sane decision about whether a task fits the budget. I want the currency, the recurrence, and the material conditions out in the open before any money moves.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Third, provisioning.&lt;/strong&gt; Even with keys and clear pricing, some services need a human to flip the actual switch. Enterprise plans love this pattern. What I look for instead is instant self-service provisioning, ideally with a status endpoint I can poll while the agent waits. A service that can go from signup to working credentials without a human in the loop is the only kind that fits this workflow.&lt;/p&gt;

&lt;p&gt;Doing all this by hand for every candidate got old fast, so now I lean on &lt;a href="https://sourcey.com" rel="noopener noreferrer"&gt;Sourcey&lt;/a&gt;, a registry that tracks exactly this. It publishes report cards that grade whether an agent can actually sign up, pay, and operate a service on its own, with the source URL and read date on every fact. The last time I checked, it listed 596 offers across 543 vendors, including startup credit programs from companies like Atlassian, Algolia, and OpenAI. It is free to read, which makes it a decent feed for an agent that needs to pick a service on its own.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fourth, documentation the agent can consume.&lt;/strong&gt; If a service only documents itself in a PDF or behind a login, my automation has nothing to work with. The services that work best publish OpenAPI specs, MCP descriptions, or clean HTML docs. A related tool I keep around for this is Sourcey's open source docs engine, which turns OpenAPI, MCP, Doxygen, godoc, rustdoc, and Markdown into a static site. When I need a stable URL to point an agent at, or a docs site that survives without a backend, it does the job, and the same registry covers its own tooling.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fifth, the exit.&lt;/strong&gt; Before money moves, I check how cancellation works. If the only path is an email to billing, the agent cannot close the loop, and the card keeps getting charged month after month. Self-service cancellation with a predictable timeline is what I want to see.&lt;/p&gt;

&lt;p&gt;The pattern across all five checks is the same. Services that are friendly to unattended agents publish everything a decision needs: keys, prices, provisioning, docs, and exits. Everyone else makes you play the human in the loop, which is fine until you have forty of these to do in an afternoon.&lt;/p&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>automation</category>
      <category>saas</category>
    </item>
  </channel>
</rss>
