<?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: Alex</title>
    <description>The latest articles on DEV Community by Alex (@alexar76).</description>
    <link>https://dev.to/alexar76</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%2F3927872%2Fdf501cac-6862-47af-8b22-4e3067696337.jpeg</url>
      <title>DEV Community: Alex</title>
      <link>https://dev.to/alexar76</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/alexar76"/>
    <language>en</language>
    <item>
      <title>One call orders the subcontract.</title>
      <dc:creator>Alex</dc:creator>
      <pubDate>Wed, 30 Sep 2026 13:04:39 +0000</pubDate>
      <link>https://dev.to/alexar76/one-call-orders-the-subcontract-13nb</link>
      <guid>https://dev.to/alexar76/one-call-orders-the-subcontract-13nb</guid>
      <description>&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fi613je4ory0r3p1w7nk1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fi613je4ory0r3p1w7nk1.png" alt="One call: prepare-pipeline, sign locally, invoke pipeline.run@v1, external agent." width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A root agent can buy a slice of work from another agent and keep the buyer relationship. The Hub routes the order. The private key never leaves the client.&lt;/p&gt;

&lt;p&gt;There are two ways to place that order over the public REST API. The long path names every Hub step. The short path collapses preparation into one request. Both end the same way: you sign locally, then you call &lt;code&gt;POST /ai-market/v2/invoke&lt;/code&gt; with capability &lt;code&gt;pipeline.run@v1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Worked example: on 29–30 September 2026, Codex ordered two external GAIA capabilities (&lt;code&gt;gaia.weather.read@v1&lt;/code&gt;, then &lt;code&gt;gaia.air.read@v1&lt;/code&gt;) through &lt;code&gt;hephaestus / pipeline.run@v1&lt;/code&gt; on &lt;a href="https://modelmarket.dev" rel="noopener noreferrer"&gt;modelmarket.dev&lt;/a&gt;. This post is the order procedure, not a product tour.&lt;/p&gt;

&lt;p&gt;Sources: Hub docs &lt;code&gt;case-study-codex-subcontract.md&lt;/code&gt; and &lt;code&gt;one-call-pipelines.md&lt;/code&gt; on the live Hub tree.&lt;/p&gt;




&lt;h2&gt;
  
  
  The short path
&lt;/h2&gt;

&lt;p&gt;Call &lt;code&gt;POST /studio/prepare-pipeline&lt;/code&gt; with the graph, optional &lt;code&gt;wallet&lt;/code&gt;, and &lt;code&gt;max_budget_usd&lt;/code&gt;. That route combines the old &lt;code&gt;/studio/preflight&lt;/code&gt; and &lt;code&gt;/studio/paid-runs/{run_id}/prepare-pipeline&lt;/code&gt;. Preparation creates no root job and sends no payment.&lt;/p&gt;

&lt;p&gt;The response carries &lt;code&gt;ready&lt;/code&gt;, &lt;code&gt;blockers&lt;/code&gt;, step identities and terms, &lt;code&gt;total_units&lt;/code&gt;, &lt;code&gt;run_id&lt;/code&gt;, &lt;code&gt;access_token&lt;/code&gt;, &lt;code&gt;graph_digest&lt;/code&gt;, &lt;code&gt;wallet&lt;/code&gt;, &lt;code&gt;expires_at&lt;/code&gt;, and &lt;code&gt;offers&lt;/code&gt; with invoice nonces and EIP-712 authorizations. A free graph needs no wallet and returns an empty &lt;code&gt;offers&lt;/code&gt; array. A paid graph without a wallet is refused.&lt;/p&gt;

&lt;p&gt;Then sign locally. The client checks the graph binding, every offer, balances, chain, pending nonces, and estimated gas. It signs EIP-3009 authorizations and EIP-1559 transactions on the client. The Hub receives signed transactions. It never receives the private key.&lt;/p&gt;

&lt;p&gt;Then send one root request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"product_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"hephaestus"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"capability_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"pipeline.run@v1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"source_hub"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"local"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"input"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"run_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;prepared-run-id&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"access_token"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;scoped-run-token&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"transactions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"weather"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0x&amp;lt;signed-transaction&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"air"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0x&amp;lt;signed-transaction&amp;gt;"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That body goes to &lt;code&gt;POST /ai-market/v2/invoke&lt;/code&gt;. The executor broadcasts a child payment only when that step is ready. Inspect &lt;code&gt;status&lt;/code&gt; and &lt;code&gt;success&lt;/code&gt;. A failed delivery is a terminal result too. An external payment is not automatically refunded.&lt;/p&gt;

&lt;p&gt;HTTP 202 means the same logical order is still pending. Retry the same signed bundle. It is not a new purchase. After completion, a repeated invoke can return the identical cached result.&lt;/p&gt;

&lt;p&gt;A GAIA-shaped prepare body looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"nodes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"weather"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"product_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"gaia.gateway"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"capability_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"gaia.weather.read@v1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"source_hub"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://iot.modelmarket.dev"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"input"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"city"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Berlin"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"air"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"product_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"gaia.gateway"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"capability_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"gaia.air.read@v1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"source_hub"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://iot.modelmarket.dev"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"input"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"city"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Berlin"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"depends_on"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"weather"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"wallet"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;buyer-address&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"max_budget_usd"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep &lt;code&gt;source_hub&lt;/code&gt; on each node. The air step waits on weather finishing. In that case study graph, weather values are not fed into the air input.&lt;/p&gt;

&lt;p&gt;If you want the client to do preparation, signing, invoke, and waiting as one operation, use &lt;code&gt;await run_pipeline(...)&lt;/code&gt; from the Hub client wheel. On the normal path that is still two primary Hub requests: prepare, then invoke. Blockchain RPC calls are additional. HTTP 202 or transport failure can mean more requests to the same order.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="s2"&gt;"aimarket-hub[client] @ https://modelmarket.dev/clients/aimarket_hub-3.14.0-py3-none-any.whl"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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;json&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;eth_account&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Account&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;aimarket_hub.pipeline_client&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;run_pipeline&lt;/span&gt;

&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;run_pipeline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;blueprint.json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="n"&gt;hub&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://modelmarket.dev&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;signer&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;PIPELINE_WALLET_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
    &lt;span class="n"&gt;rpc_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://mainnet.base.org&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;max_total_usd&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;state_path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;order.private.json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;wait&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="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;final_result&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bill_of_materials&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Put the wallet key in the environment yourself. Do not paste it into a tool argument. The recovery file holds scoped credentials and signed transactions; it does not hold the private key. Keep it private.&lt;/p&gt;




&lt;h2&gt;
  
  
  The long path
&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwiznlfhbnxobbxkcnf68.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwiznlfhbnxobbxkcnf68.png" alt="Five named steps on the long REST path, including HTTP 202 retry." width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Before &lt;code&gt;prepare-pipeline&lt;/code&gt; existed as one route, the case study did this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;POST /studio/preflight&lt;/code&gt; with the blueprint, preserving &lt;code&gt;source_hub&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;POST /studio/paid-runs/{run_id}/prepare-pipeline&lt;/code&gt; with the buyer address.&lt;/li&gt;
&lt;li&gt;Check balances, Base chain ID &lt;strong&gt;8453&lt;/strong&gt;, recipients, amounts, and gas. Sign EIP-3009 and EIP-1559 locally.&lt;/li&gt;
&lt;li&gt;Submit &lt;code&gt;pipeline.run@v1&lt;/code&gt; to &lt;code&gt;POST /ai-market/v2/invoke&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Continue the same run after HTTP 202 while confirmations are pending.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Those old endpoints remain available. The new prepare route is advertised on the manifest as &lt;code&gt;pipeline_execution.prepare_graph&lt;/code&gt;. Prefer it for a new order.&lt;/p&gt;




&lt;h2&gt;
  
  
  What crosses the boundary
&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpwpjyn6sp9i6r4bp48mk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpwpjyn6sp9i6r4bp48mk.png" alt="Caller keeps the buyer; root orders the graph; external capability returns a receipt." width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The caller keeps the buyer relationship: wallet, signatures, &lt;code&gt;run_id&lt;/code&gt;, scoped &lt;code&gt;access_token&lt;/code&gt;. The root capability orders the graph and pays each child when that step is ready. The external capability does one priced slice. A signed result and a receipt come back into the SUB/1 job tree. Children are marked &lt;code&gt;funded_by: own&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A successful response contains the final result, signed bill, root receipt, and SUB/1 tree. Status reads do not send money. &lt;code&gt;GET /studio/paid-runs/{run_id}/pipeline&lt;/code&gt; with &lt;code&gt;X-Studio-Run-Token&lt;/code&gt; reads the root result without invoking children.&lt;/p&gt;

&lt;p&gt;Obtain fresh quotes and authorizations for a new order. Recorded run IDs and transaction hashes are historical evidence, not reusable payment credentials.&lt;/p&gt;




&lt;h2&gt;
  
  
  What the Codex order returned
&lt;/h2&gt;

&lt;p&gt;Both GAIA children succeeded in the recorded tests. Services cost &lt;strong&gt;0.002 USDC&lt;/strong&gt; on Base mainnet. With network fees, the totals observed were about &lt;strong&gt;$0.0048&lt;/strong&gt; (29 Sep) and &lt;strong&gt;$0.0047&lt;/strong&gt; (30 Sep one-call path), inside a $1 limit. The Hub was seller of record. GAIA and the Hub belong to the same operated ecosystem; the runs demonstrate execution and settlement with real funds, not independent customer demand from a separately owned seller.&lt;/p&gt;

&lt;p&gt;Public evidence bundles in the Hub docs include signed results and chain receipts. They do not include wallet private keys, run access tokens, or raw signed payment transactions.&lt;/p&gt;




&lt;p&gt;Landing: &lt;a href="https://modelmarket.dev" rel="noopener noreferrer"&gt;modelmarket.dev&lt;/a&gt;. Client: install the wheel above, then &lt;code&gt;aimarket-pipeline --help&lt;/code&gt;. For a resume after signing: &lt;code&gt;run_pipeline(resume=True, state_path="order.private.json")&lt;/code&gt; — no signer required once the bundle is saved.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>tutorial</category>
      <category>api</category>
      <category>ai</category>
    </item>
    <item>
      <title>Price the chain before hop three bills you.</title>
      <dc:creator>Alex</dc:creator>
      <pubDate>Tue, 29 Sep 2026 17:14:27 +0000</pubDate>
      <link>https://dev.to/alexar76/price-the-chain-before-hop-three-bills-you-4jfm</link>
      <guid>https://dev.to/alexar76/price-the-chain-before-hop-three-bills-you-4jfm</guid>
      <description>&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2zubc6mn63hlvh7sgzea.jpg" 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2zubc6mn63hlvh7sgzea.jpg" alt="Price the chain before hop three bills you." width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One capability has one price on the row. A chain does not. An earlier hop can succeed and settle, and the next hop can be the one that stops the walk. Anything after that was never called. The bill is the surprise. The price of the whole chain is knowable before you press Run.&lt;/p&gt;

&lt;p&gt;HEPHAESTUS is the forge for that.&lt;/p&gt;

&lt;p&gt;Landing: &lt;a href="https://forge.modelmarket.dev/" rel="noopener noreferrer"&gt;forge.modelmarket.dev&lt;/a&gt;. The page: &lt;a href="https://modelmarket.dev/studio/" rel="noopener noreferrer"&gt;modelmarket.dev/studio&lt;/a&gt;. No account. The function that costs a graph is &lt;a href="https://github.com/alexar76/aicom/blob/main/hephaestus/src/estimate.ts" rel="noopener noreferrer"&gt;&lt;code&gt;estimateBlueprint&lt;/code&gt;&lt;/a&gt; in &lt;code&gt;hephaestus/src/estimate.ts&lt;/code&gt;. No dependencies. No DOM.&lt;/p&gt;




&lt;h2&gt;
  
  
  Read the header before Run
&lt;/h2&gt;

&lt;p&gt;The studio does not open on an empty canvas. It discovers a chain from the live catalogue: a hop whose declared output fills the next hop's required fields, wired by those field names. If nothing pairs, it opens on one priced hop instead of three red errors.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Start&lt;/code&gt; and &lt;code&gt;Result&lt;/code&gt; are markers on the canvas. They are not hops. They are not billed. Only capability nodes travel to the executor.&lt;/p&gt;

&lt;p&gt;The header is the estimate: a dollar sum, a hop count, and a latency written with &lt;code&gt;≥&lt;/code&gt;. Steps run one after another, so that latency is a floor. It is the number a parallel executor could not beat, and it is not a forecast. A capability with no declared latency counts as zero on that path and is named separately, so the floor is not inflated by a guess.&lt;/p&gt;

&lt;p&gt;Money is summed in integer micro-dollars, one million per dollar. The catalogue's real prices are fractions of a cent. Adding them as floats drifts in the digits the total is made of. An unpriced capability is counted and named. Its cost is unknown. It is not zero, and it is left out of the sum.&lt;/p&gt;

&lt;p&gt;The price used for a hop is the routed price when the hub routes to a peer, otherwise the price the provider asks. Estimating only the base price under-quotes every federated hop by the routing fee.&lt;/p&gt;

&lt;p&gt;An estimate is not a quote. It is the signed manifest at the moment you read it. A provider can reprice before the run.&lt;/p&gt;

&lt;p&gt;The page refuses a graph the executor cannot run. At most 16 capabilities. A hop may wait on several parents, and exactly one of those connections may carry data. A second data parent used to mean "whichever hop the sort finished last," which could be drawn, priced, and fed from the wrong upstream.&lt;/p&gt;




&lt;h2&gt;
  
  
  What one finished chain recorded
&lt;/h2&gt;

&lt;p&gt;This bill is public. Two hops, both successful, both &lt;code&gt;payer: "trial"&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://magic-ai-factory.com/ai-market/pipelines/tr_6dcceda217c3" rel="noopener noreferrer"&gt;magic-ai-factory.com/ai-market/pipelines/tr_6dcceda217c3&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The steps on that object:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;gaia.weather.read@v1&lt;/code&gt; — &lt;code&gt;price_usd&lt;/code&gt; 0.001&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;gaia.verify@v1&lt;/code&gt; — &lt;code&gt;price_usd&lt;/code&gt; 0.002&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;total_usd&lt;/code&gt; is 0.003. &lt;code&gt;blame&lt;/code&gt; is null, because nothing failed. Those figures are what that trace recorded. They are not today's price list. Open the studio and read the header.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;payer&lt;/code&gt; on a hop is &lt;code&gt;local&lt;/code&gt;, &lt;code&gt;trial&lt;/code&gt;, &lt;code&gt;channel&lt;/code&gt;, or &lt;code&gt;unpaid&lt;/code&gt;. A trial run is not signed evidence that the factory bought the hop. The hub meters a renewing allowance against the visitor id the browser sends. The executor does not attach its own credential to an unauthenticated Run.&lt;/p&gt;

&lt;p&gt;While this was written, a fresh visitor's live quota was 5 trials in an hourly window. That meter is a trial, not an account. A hop that composes its answer with a paid model is outside it and comes back asking for payment. With no allowance and no channel of your own, the hop fails with a reason. The estimate still says what it would have cost.&lt;/p&gt;




&lt;h2&gt;
  
  
  When a hop breaks, the bill names that hop
&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjg6pzepg816ydemt8cjs.jpg" 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjg6pzepg816ydemt8cjs.jpg" alt="at_fault, not_at_fault, not_executed, total_usd." width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The executor walks the graph in dependency order. A hop that does not return success stops the walk. Hops that already returned success stay on the bill, and their prices are what &lt;code&gt;total_usd&lt;/code&gt; sums. Hops that had not started are listed under &lt;code&gt;not_executed&lt;/code&gt;. They were not called.&lt;/p&gt;

&lt;p&gt;The blame block is hop-level:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"policy"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"hop-level"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"at_fault"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"…"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"capability_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"…"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"status_code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"not_at_fault"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"…"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"not_executed"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"…"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A public example of that block is a single hop that returned HTTP 502 and no price, so the total stayed 0:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://magic-ai-factory.com/ai-market/pipelines/tr_2419b38af676" rel="noopener noreferrer"&gt;magic-ai-factory.com/ai-market/pipelines/tr_2419b38af676&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;at_fault&lt;/code&gt; is &lt;code&gt;gaia.weather.read@v1&lt;/code&gt;. &lt;code&gt;not_at_fault&lt;/code&gt; and &lt;code&gt;not_executed&lt;/code&gt; are empty, because nothing succeeded before it and nothing was waiting after it. When a later hop is the one that breaks, the earlier ids are the ones cleared, and the rest are named as not executed.&lt;/p&gt;

&lt;p&gt;One refusal happens before a provider is called. If a &lt;code&gt;${hop.field}&lt;/code&gt; reference cannot be filled from what the earlier hop actually returned, that step is recorded with status 0 and price 0. The literal &lt;code&gt;${…}&lt;/code&gt; is not posted to a paid provider.&lt;/p&gt;




&lt;h2&gt;
  
  
  The signature covers the bill, not the wrapper
&lt;/h2&gt;

&lt;p&gt;The executor signs the bill with Ed25519. The signed bytes are the UTF-8 of one JSON object: keys sorted, a comma between members, a colon after a key, no spaces. The &lt;code&gt;signature&lt;/code&gt; field is not in that object. The signature value is base64. The function is &lt;code&gt;sign_payload&lt;/code&gt; in &lt;a href="https://github.com/alexar76/aicom/blob/main/web/backend/services/ai_market_protocol/signing.py" rel="noopener noreferrer"&gt;&lt;code&gt;signing.py&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;GET /ai-market/pipelines/{trace_id}&lt;/code&gt; returns that object and then adds &lt;code&gt;protocol_version&lt;/code&gt;. That field is not inside the signed object. Drop it, and drop &lt;code&gt;signature&lt;/code&gt;, before you treat the remainder as what was signed.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;GET /ai-market/pipelines&lt;/code&gt; is a different document. It is a projection: cost, hops, status, blame. It drops &lt;code&gt;channel_id&lt;/code&gt; and each hop's &lt;code&gt;receipt_nonce&lt;/code&gt;. A nonce is the lookup key for a public receipt, and the list is not a feed of those keys. The projection says where the signed bill lives. It is not the signed artefact.&lt;/p&gt;

&lt;p&gt;The factory's signing key is &lt;code&gt;signer_public_key&lt;/code&gt; on &lt;a href="https://magic-ai-factory.com/.well-known/ai-market.json" rel="noopener noreferrer"&gt;magic-ai-factory.com/.well-known/ai-market.json&lt;/a&gt;. Pin the key you verify against. A key carried inside a document is a claim.&lt;/p&gt;

&lt;p&gt;A signed bill proves what this executor recorded. It does not prove the hop's answer was true. That is a different capability, and you can put one in the graph. The two-hop bill above is a read followed by a verify.&lt;/p&gt;

&lt;p&gt;The page is a convenience. It can put the same request JSON on the clipboard. The hub serves the studio because the hub's CORS is fail-closed: a page on another origin cannot read the catalogue at all.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>tutorial</category>
      <category>webdev</category>
      <category>ai</category>
    </item>
    <item>
      <title>The receipt is seven fields. The hub can wait.</title>
      <dc:creator>Alex</dc:creator>
      <pubDate>Sun, 27 Sep 2026 20:34:44 +0000</pubDate>
      <link>https://dev.to/alexar76/the-receipt-is-seven-fields-the-hub-can-wait-bom</link>
      <guid>https://dev.to/alexar76/the-receipt-is-seven-fields-the-hub-can-wait-bom</guid>
      <description>&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F50yl5p260zv7t2iarfbj.jpg" 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F50yl5p260zv7t2iarfbj.jpg" alt="Seven fields. One signature. Any language." width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A marketplace is a long project. A signed receipt is a string.&lt;/p&gt;

&lt;p&gt;If you already hold a JSON receipt from an AIMarket hub, you can check the signature in your own stack this weekend. You do not need to reimplement the hub, stand up a second one, or read the Python reference. The bytes are written down. The files that decide whether you got them right are already in git.&lt;/p&gt;

&lt;p&gt;Repo: &lt;a href="https://github.com/alexar76/aimarket-protocol" rel="noopener noreferrer"&gt;alexar76/aimarket-protocol&lt;/a&gt;. Dual license, Apache-2.0 OR MIT. Spec section that matters: &lt;a href="https://github.com/alexar76/aimarket-protocol/blob/main/spec.md" rel="noopener noreferrer"&gt;§7.3&lt;/a&gt;. Vectors: &lt;a href="https://github.com/alexar76/aimarket-protocol/tree/main/test-vectors" rel="noopener noreferrer"&gt;&lt;code&gt;test-vectors/&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This is one slice of the protocol. Passing it does not make a hub, and it does not make anyone "certified." There is no conformance badge to collect. There is a yes/no on seven files.&lt;/p&gt;




&lt;h2&gt;
  
  
  What you are checking
&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fl2e0akiktepbj16mt1l9.jpg" 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fl2e0akiktepbj16mt1l9.jpg" alt="The signed string is the whole argument." width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Every signature in this protocol is Ed25519 over the UTF-8 of one canonical string. The result is standard base64, with padding. The string is &lt;code&gt;name:value&lt;/code&gt; pairs joined by &lt;code&gt;|&lt;/code&gt;, in a fixed order, with no spaces.&lt;/p&gt;

&lt;p&gt;A v1 receipt signs exactly this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nonce:{nonce}|product_id:{product_id}|capability_id:{capability_id}|price_usd:{price_usd}|timestamp:{timestamp}|success:{0|1}|latency_ms:{latency_ms}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The published vector &lt;a href="https://github.com/alexar76/aimarket-protocol/blob/main/test-vectors/receipt-signed.json" rel="noopener noreferrer"&gt;&lt;code&gt;receipt-signed.json&lt;/code&gt;&lt;/a&gt; signs this exact line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nonce:rcpt_test001|product_id:prod-001|capability_id:translate.multi@v2|price_usd:0.4|timestamp:2026-08-28T09:00:50Z|success:1|latency_ms:8100
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The JSON says &lt;code&gt;"success": true&lt;/code&gt;. The signed bytes say &lt;code&gt;success:1&lt;/code&gt;. &lt;code&gt;true&lt;/code&gt; and &lt;code&gt;false&lt;/code&gt; never appear in the string. A missing &lt;code&gt;success&lt;/code&gt; is &lt;code&gt;0&lt;/code&gt;. A missing &lt;code&gt;latency_ms&lt;/code&gt; is &lt;code&gt;0&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Build that string from the file. Verify it with the pinned public key below. If your string differs by one character, the signature is wrong, and that is the test working.&lt;/p&gt;




&lt;h2&gt;
  
  
  The key is not inside the receipt
&lt;/h2&gt;

&lt;p&gt;Pin this public key. It is the test key, published so the vectors are reproducible. Do not use it in production. Do not copy the private key out of &lt;code&gt;test-vectors/README.md&lt;/code&gt; into anything that ships.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;11qYAYKxCrfVS/7TyWQHOg7hcvPapiMlrwIaaPcHURo=
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;signature.public_key&lt;/code&gt; inside a receipt is a claim. A verifier that trusts it will accept a signature from whoever generated the file. The test key lives beside the vectors. A production key lives in your config, pinned by you.&lt;/p&gt;




&lt;h2&gt;
  
  
  Four ways a careful parser still fails
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Numbers are tokens.&lt;/strong&gt; &lt;code&gt;price_usd&lt;/code&gt; and &lt;code&gt;latency_ms&lt;/code&gt; are copied as the exact JSON number text. The v2 vector signs &lt;code&gt;price_usd:0.0&lt;/code&gt;, not &lt;code&gt;price_usd:0&lt;/code&gt;. Parse the number, print it from a float, and those two stop being the same string.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A rejection is a longer string.&lt;/strong&gt; &lt;a href="https://github.com/alexar76/aimarket-protocol/blob/main/test-vectors/receipt-v2-signed.json" rel="noopener noreferrer"&gt;&lt;code&gt;receipt-v2-signed.json&lt;/code&gt;&lt;/a&gt; carries &lt;code&gt;"type": "rejection"&lt;/code&gt; and &lt;code&gt;"signature.version": 2&lt;/code&gt;. Its canonical line is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nonce:rcpt_test002|product_id:prod-001|capability_id:translate.multi@v2|price_usd:0.0|timestamp:2026-08-28T09:00:50Z|success:0|latency_ms:0|v:2|fields:62e8135ac924809d58b3b8d8e8e0ff9b3bdaaabca378881003524c36408a61aa
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;fields&lt;/code&gt; digest is SHA-256, lowercase hex, over one JSON object. The keys are:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type, channel_id, category, plugin, reason, verify_score, delivery_reasons, trace_id, refunded
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A key that is absent is JSON &lt;code&gt;null&lt;/code&gt;, not omitted. The object is serialized with sorted keys, &lt;code&gt;ensure_ascii&lt;/code&gt; off, and compact separators: a comma between members, a colon after a key. No spaces. Sorted, the hashed order is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;category, channel_id, delivery_reasons, plugin, reason, refunded, trace_id, type, verify_score
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Manifest digests elsewhere in the same spec use a space after &lt;code&gt;:&lt;/code&gt; and &lt;code&gt;,&lt;/code&gt;. Receipt fields do not. One helper for both will verify one of them and fail the other.&lt;/p&gt;

&lt;p&gt;Read the version from &lt;code&gt;signature.version&lt;/code&gt;. It is the JSON integer &lt;code&gt;2&lt;/code&gt; on this file. Do not infer it from a header.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Non-ASCII stays non-ASCII.&lt;/strong&gt; The digest emits characters as themselves. A serializer that writes &lt;code&gt;\uXXXX&lt;/code&gt; produces a different hash, and every v2 signature fails.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The downgrade file is not a clean accept.&lt;/strong&gt; &lt;a href="https://github.com/alexar76/aimarket-protocol/blob/main/test-vectors/negative/receipt-v2-downgraded-to-v1.json" rel="noopener noreferrer"&gt;&lt;code&gt;receipt-v2-downgraded-to-v1.json&lt;/code&gt;&lt;/a&gt; carries v2 fields under a signature that does not cover them. A weekend verifier that does not need to speak to old peers should refuse it. If you accept the v1 half, you still have to say which of those fields are unsigned. A bare "ok" on that file is a fail.&lt;/p&gt;




&lt;h2&gt;
  
  
  The seven files
&lt;/h2&gt;

&lt;p&gt;Accept:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;test-vectors/receipt-signed.json&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;test-vectors/receipt-v2-signed.json&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Reject:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;test-vectors/negative/receipt-flipped-success.json&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;test-vectors/negative/receipt-tampered-latency.json&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;test-vectors/negative/receipt-stale-timestamp.json&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;test-vectors/negative/receipt-wrong-signer.json&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;test-vectors/negative/receipt-v2-downgraded-to-v1.json&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Language is yours. Go, Rust, C#, Kotlin, TypeScript, whatever you already run. The thing that does not count is a wrapper around &lt;a href="https://github.com/alexar76/aimarket-hub" rel="noopener noreferrer"&gt;aimarket-hub&lt;/a&gt;. Start from &lt;code&gt;spec.md&lt;/code&gt; §7.3 and the vectors. Leave the hub repo closed.&lt;/p&gt;

&lt;p&gt;Vectors are necessary. They are not the whole protocol. Invoke, federation, and payment channels are other slices. This weekend is the receipt.&lt;/p&gt;




&lt;h2&gt;
  
  
  What counts
&lt;/h2&gt;

&lt;p&gt;An implementation counts here when three things are true:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The author is not &lt;a href="https://github.com/alexar76" rel="noopener noreferrer"&gt;alexar76&lt;/a&gt;. A second copy written by the maintainer, in any language, does not add one.&lt;/li&gt;
&lt;li&gt;The code is not derived from the reference hub.&lt;/li&gt;
&lt;li&gt;The seven files above do what the table says, and the repo is public.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Shared governance of the spec, as written in &lt;a href="https://github.com/alexar76/aimarket-protocol/blob/main/GOVERNANCE.md" rel="noopener noreferrer"&gt;&lt;code&gt;GOVERNANCE.md&lt;/code&gt;&lt;/a&gt;, waits on three implementations the maintainer does not operate, at least two of them not grown from the reference. A receipt checker is one slice toward that, not the institution. No foundation, no badge, no grant program in this post.&lt;/p&gt;

&lt;p&gt;When yours passes, open an issue on the protocol repo:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/alexar76/aimarket-protocol/issues/new" rel="noopener noreferrer"&gt;https://github.com/alexar76/aimarket-protocol/issues/new&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Title: &lt;code&gt;receipt: &amp;lt;language&amp;gt;&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Language:
Repo:
I am not alexar76. This is not a wrapper of aimarket-hub.

Accepts receipt-signed.json and receipt-v2-signed.json.
Rejects the five negative receipt files listed in the challenge.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That issue is the count. A star on the spec repo is optional, and it is not a substitute for the link.&lt;/p&gt;

&lt;p&gt;If your string matches the published canonical and the signature still fails, the bug is worth an issue too. Bring the string you signed. Do not bring a patch that makes the vector match the hub.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>security</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Catalogue process. Snapshot memory.</title>
      <dc:creator>Alex</dc:creator>
      <pubDate>Sun, 27 Sep 2026 09:08:06 +0000</pubDate>
      <link>https://dev.to/alexar76/catalogue-process-snapshot-memory-28hc</link>
      <guid>https://dev.to/alexar76/catalogue-process-snapshot-memory-28hc</guid>
      <description>&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fg6xius81z9zvyd55jo8x.jpg" 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fg6xius81z9zvyd55jo8x.jpg" alt="Two new rooms — HESTIA hearth and HISTOR record" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Most agent posts sell a chat window with plugins.&lt;/p&gt;

&lt;p&gt;AIMarket keeps shipping &lt;strong&gt;rooms&lt;/strong&gt;: a factory that builds, a Hub that lists and settles, desks that refuse poisoned tools. Two newer rooms close gaps the earlier map left open —&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://hestia.modelmarket.dev/" rel="noopener noreferrer"&gt;HESTIA&lt;/a&gt;&lt;/strong&gt; is the &lt;strong&gt;hearth&lt;/strong&gt;: where a seller process actually runs.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;&lt;a href="https://histor.modelmarket.dev/" rel="noopener noreferrer"&gt;HISTOR&lt;/a&gt;&lt;/strong&gt; is the &lt;strong&gt;record&lt;/strong&gt;: what remote MCP endpoints advertised in &lt;code&gt;tools/list&lt;/code&gt;, signed and dated.&lt;/p&gt;

&lt;p&gt;Crypto stays off the titles. The shape is deploy → announce → receipt, and observe → digest → diff.&lt;/p&gt;

&lt;p&gt;Live map: &lt;a href="https://modeldev.modelmarket.dev/" rel="noopener noreferrer"&gt;modeldev.modelmarket.dev&lt;/a&gt; · Monorepo: &lt;a href="https://github.com/alexar76/aicom" rel="noopener noreferrer"&gt;github.com/alexar76/aicom&lt;/a&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  The hole a catalogue cannot fill
&lt;/h2&gt;

&lt;p&gt;A Hub row answers &lt;em&gt;what can a buyer find&lt;/em&gt;. It does not answer &lt;em&gt;is a process listening on a stable URL right now&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;create-aimarket-agent&lt;/code&gt; scaffolds a signed Protocol v2 provider on disk. Until something hosts it, nobody is listening. A forgotten tmux on a laptop is not a market.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HESTIA&lt;/strong&gt; is that host. Isolated process. Stable &lt;code&gt;/t/{slug}&lt;/code&gt;. Ed25519 at the edge. Announce to the Hub only when you ask — never as a trust grant.&lt;/p&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fws9ln8rcf2lrjmti4s60.jpg" 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fws9ln8rcf2lrjmti4s60.jpg" alt="HESTIA live landing — hosting control plane" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Reference hearth: &lt;a href="https://hestia.modelmarket.dev/" rel="noopener noreferrer"&gt;hestia.modelmarket.dev&lt;/a&gt; · Source: &lt;a href="https://github.com/alexar76/hestia" rel="noopener noreferrer"&gt;github.com/alexar76/hestia&lt;/a&gt; (MIT)&lt;/p&gt;

&lt;p&gt;Today the public roster is not empty. Three tenants are running on the reference hearth — commit-reveal referee, canonical JSON, policy decide — each with a public URL. &lt;code&gt;announced: false&lt;/code&gt; on purpose until someone knocks. Empty roster means &lt;em&gt;nothing is hosted here&lt;/em&gt;, not &lt;em&gt;the market is empty&lt;/em&gt;.&lt;/p&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1bp9rq4tu2jvztnbfb8h.jpg" 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1bp9rq4tu2jvztnbfb8h.jpg" alt="HESTIA console — deploy is a write; roster is public" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Deploy ≠ list
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Step&lt;/th&gt;
&lt;th&gt;What it is&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Scaffold&lt;/td&gt;
&lt;td&gt;CLI / Factory → signed bundle on disk&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deploy&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;POST&lt;/code&gt; onto a Hestia hearth → process behind &lt;code&gt;/t/{slug}&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Admit (optional)&lt;/td&gt;
&lt;td&gt;THEMIS can refuse a start&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Announce&lt;/td&gt;
&lt;td&gt;Explicit knock. Hub may crawl. Not a trust badge.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Buy&lt;/td&gt;
&lt;td&gt;Hub catalogue + receipt — still the till&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Do &lt;strong&gt;not&lt;/strong&gt; paste a deploy token into the public reference &lt;code&gt;/ui/&lt;/code&gt; unless you operate that host. Self-host with your own token. Workshop: ninety minutes at your console — &lt;a href="https://github.com/alexar76/hestia/blob/main/docs/workshop.md" rel="noopener noreferrer"&gt;docs/workshop&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;HESTIA_DEPLOY_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;python3 &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s1"&gt;'import secrets; print(secrets.token_urlsafe(24))'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="c"&gt;# from the hestia/ tree&lt;/span&gt;
uv &lt;span class="nb"&gt;sync&lt;/span&gt; &lt;span class="nt"&gt;--extra&lt;/span&gt; dev &lt;span class="nt"&gt;--project&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
uv run &lt;span class="nt"&gt;--project&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; python &lt;span class="nt"&gt;-m&lt;/span&gt; hestia
&lt;span class="c"&gt;# http://127.0.0.1:9480/ui/  ·  GET /v1/hearth&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Five questions. Five desks.
&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2p6k7cil1u6ukvyqnnrl.jpg" 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2p6k7cil1u6ukvyqnnrl.jpg" alt="Do not collapse the layers" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Desk&lt;/th&gt;
&lt;th&gt;Question&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Factory / CLI&lt;/td&gt;
&lt;td&gt;Scaffold a provider?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;THEMIS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Admit this into a Hub catalogue?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;HESTIA&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Where does the seller process run?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Hub&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;What can a buyer find and pay for?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;HISTOR&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;What did &lt;code&gt;tools/list&lt;/code&gt; say — and when did it change?&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A hearth URL is &lt;strong&gt;not&lt;/strong&gt; a catalogue row. A WARDEN block is &lt;strong&gt;not&lt;/strong&gt; a HISTOR label. Collapsing those words is how a clean report hides a rewritten tool description.&lt;/p&gt;




&lt;h2&gt;
  
  
  The hole a snapshot cannot fill
&lt;/h2&gt;

&lt;p&gt;We already measured the public MCP registry once. &lt;a href="https://dev.to/alexar76/we-scanned-1108-public-mcp-servers-warden-blocked-50-only-4-were-real-hp0"&gt;WARDEN scanned 1,108 servers&lt;/a&gt;, blocked 50, and published that only 4 of those blocks were the kind of real risk that framing wanted.&lt;/p&gt;

&lt;p&gt;That was a moment. A server can pass the moment and change one sentence in a tool description the next day.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HISTOR&lt;/strong&gt; is Certificate Transparency for MCP tool definitions: read &lt;code&gt;initialize&lt;/code&gt; and &lt;code&gt;tools/list&lt;/code&gt;, never call a tool, sign what was seen, append, tell you when the digest changed.&lt;/p&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fb3cibddcd9fg1urm6znu.jpg" 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fb3cibddcd9fg1urm6znu.jpg" alt="HISTOR live desk — public memory of MCP tool defs" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Deep dive (method + four labels): &lt;a href="https://dev.to/alexar76/11749-mcp-servers-answered-toolslist-the-signed-log-still-says-yesterday-42e1"&gt;11,749 MCP servers answered tools/list…&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The log grew. The method didn't.
&lt;/h3&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9eogdcr4mvw9rpt06hm3.jpg" 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9eogdcr4mvw9rpt06hm3.jpg" alt="HISTOR sealed crawl counts" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Last &lt;strong&gt;sealed&lt;/strong&gt; crawl finished &lt;strong&gt;2026-09-26 11:43 UTC&lt;/strong&gt;. Counters from the live desk / API at write time:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Count&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Answered &lt;code&gt;tools/list&lt;/code&gt; (&lt;code&gt;ok&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;12,201&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Signed labels in the tree&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;101,192&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Definition changes, 7 days&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;4,463&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Endpoints that ever changed&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;3,581&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A crawl that has not finished has not sealed. Quoting a mid-crawl counter is a lie by the time you finish the paragraph. The desk is the number; this page is the method.&lt;/p&gt;

&lt;p&gt;A change on the desk is amber and dated — added, removed, or a field rewritten. Never the words &lt;em&gt;compromised&lt;/em&gt; or &lt;em&gt;unsafe&lt;/em&gt;. What you do with it is yours: re-read, re-approve, or pin the old digest.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-sS&lt;/span&gt; https://histor.modelmarket.dev/api/v1/check &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"endpoint":"https://example.com/mcp","tools":[ …tools/list you received… ]}'&lt;/span&gt;

curl &lt;span class="nt"&gt;-sS&lt;/span&gt; https://histor.modelmarket.dev/api/v1/log/sth
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Live: &lt;a href="https://histor.modelmarket.dev/" rel="noopener noreferrer"&gt;histor.modelmarket.dev&lt;/a&gt; · Source: &lt;a href="https://github.com/alexar76/histor" rel="noopener noreferrer"&gt;github.com/alexar76/histor&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Soft close
&lt;/h2&gt;

&lt;p&gt;If the Hub alone is a wall of doors, the hearth is heat behind one of them — and the record is the guestbook that outlives yesterday's crawl.&lt;/p&gt;

&lt;p&gt;Walk them once:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open &lt;a href="https://hestia.modelmarket.dev/" rel="noopener noreferrer"&gt;hestia.modelmarket.dev&lt;/a&gt; — see a running roster that is not the catalogue
&lt;/li&gt;
&lt;li&gt;Open &lt;a href="https://histor.modelmarket.dev/" rel="noopener noreferrer"&gt;histor.modelmarket.dev&lt;/a&gt; — paste a &lt;code&gt;tools/list&lt;/code&gt;, ask for a match
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;⭐ &lt;a href="https://github.com/alexar76/hestia" rel="noopener noreferrer"&gt;github.com/alexar76/hestia&lt;/a&gt; · &lt;a href="https://github.com/alexar76/histor" rel="noopener noreferrer"&gt;github.com/alexar76/histor&lt;/a&gt; · map: &lt;a href="https://modeldev.modelmarket.dev/" rel="noopener noreferrer"&gt;modeldev.modelmarket.dev&lt;/a&gt;&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>opensource</category>
      <category>ai</category>
      <category>security</category>
    </item>
    <item>
      <title>11,749 MCP servers answered tools/list. The signed log still says yesterday.</title>
      <dc:creator>Alex</dc:creator>
      <pubDate>Thu, 24 Sep 2026 11:40:47 +0000</pubDate>
      <link>https://dev.to/alexar76/11749-mcp-servers-answered-toolslist-the-signed-log-still-says-yesterday-42e1</link>
      <guid>https://dev.to/alexar76/11749-mcp-servers-answered-toolslist-the-signed-log-still-says-yesterday-42e1</guid>
      <description>&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F06ib34lqd0rufxmvd11n.jpg" 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F06ib34lqd0rufxmvd11n.jpg" alt="On the record — HISTOR, the public memory of MCP tool definitions" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We already measured the public registry once. &lt;a href="https://dev.to/alexar76/we-scanned-1108-public-mcp-servers-warden-blocked-50-only-4-were-real-hp0"&gt;WARDEN scanned 1,108 servers&lt;/a&gt;, blocked 50, and published that only 4 of those blocks were real.&lt;/p&gt;

&lt;p&gt;That was a snapshot. A server can pass that snapshot and change one sentence in a tool description the next day. Your client will hand the new sentence to the model without asking you again.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://histor.modelmarket.dev/" rel="noopener noreferrer"&gt;HISTOR&lt;/a&gt;&lt;/strong&gt; is the public memory of what remote MCP endpoints in the official registry advertised. It reads &lt;code&gt;initialize&lt;/code&gt; and &lt;code&gt;tools/list&lt;/code&gt;. It never calls a tool. It signs what it saw, appends it, and tells you when the digest changed.&lt;/p&gt;

&lt;p&gt;Live: &lt;a href="https://histor.modelmarket.dev/" rel="noopener noreferrer"&gt;histor.modelmarket.dev&lt;/a&gt; · Source: &lt;a href="https://github.com/alexar76/histor" rel="noopener noreferrer"&gt;github.com/alexar76/histor&lt;/a&gt; (MIT)&lt;/p&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsd90fpnsrlvpzvs3jvew.jpg" 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsd90fpnsrlvpzvs3jvew.jpg" alt="Live HISTOR desk — every MCP server's tools, on the record" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The last crawl that actually sealed
&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F613m4xhebrim2lb1jo44.jpg" 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F613m4xhebrim2lb1jo44.jpg" alt="State of MCP — last completed crawl, 23 September 2026" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These figures are from the last &lt;strong&gt;completed&lt;/strong&gt; crawl, finished &lt;strong&gt;2026-09-23 11:33 UTC&lt;/strong&gt;. The desk says so. A newer crawl was still running while this was written, and its counters were climbing. They are not in the signed tree yet.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Count&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Remote endpoints in the registry&lt;/td&gt;
&lt;td&gt;21,742&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Endpoints dialled&lt;/td&gt;
&lt;td&gt;20,445&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Answered &lt;code&gt;tools/list&lt;/code&gt; (&lt;code&gt;ok&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;11,749&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Asked for a login (&lt;code&gt;http-401&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;4,753&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rate-limited (&lt;code&gt;http-429&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;1,544&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Labels in the signed log&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;33,928&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Client reports, 7 days&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Eleven thousand seven hundred forty-nine servers handed over a tool list. Nothing was installed. No tool was invoked. Private addresses are refused before a connection opens.&lt;/p&gt;

&lt;p&gt;The 4,753 login walls stay on the list as &lt;strong&gt;not observed&lt;/strong&gt;. They are counted. They are not dropped, and they are not treated as a quiet pass.&lt;/p&gt;

&lt;p&gt;The signed tree head at shoot time was still that September 23 head: size &lt;strong&gt;33,928&lt;/strong&gt;, root &lt;code&gt;acca0547…&lt;/code&gt;. A crawl that has not finished has not sealed. The log only grows when a head is signed.&lt;/p&gt;




&lt;h2&gt;
  
  
  A change is a date and a diff
&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F49j0oz9zripy5u5tc2jw.jpg" 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F49j0oz9zripy5u5tc2jw.jpg" alt="Tool-definition changes — a date and a diff, not an accusation" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While the new crawl was in progress, the desk was already showing definition changes: tools added, tools removed, schema sentences rewritten. The 7-day counter moved past a thousand and kept moving. Quoting one number from the middle of a crawl would be a lie by the time you finish this paragraph. The live desk is the number. This page is the method.&lt;/p&gt;

&lt;p&gt;What a change looks like on the desk:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;amber, dated&lt;/li&gt;
&lt;li&gt;a per-tool diff — added, removed, or a field inside a description or a schema&lt;/li&gt;
&lt;li&gt;never the words compromised, rug pull, or unsafe&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A description that updates a tool count is a change. So is one new sentence. What you do with it is yours: re-read, re-approve, or pin the old digest.&lt;/p&gt;




&lt;h2&gt;
  
  
  Four labels. Three of them never fail.
&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fud1kb4idxwi8jyandb0r.jpg" 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fud1kb4idxwi8jyandb0r.jpg" alt="Four labels — observation, pattern scan, continuity, name" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Label&lt;/th&gt;
&lt;th&gt;What it commits to&lt;/th&gt;
&lt;th&gt;&lt;code&gt;fail&lt;/code&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Observation&lt;/td&gt;
&lt;td&gt;The tool set was drained and digested&lt;/td&gt;
&lt;td&gt;never&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pattern scan&lt;/td&gt;
&lt;td&gt;Which published WARDEN patterns matched the text&lt;/td&gt;
&lt;td&gt;never — a match is &lt;code&gt;inconclusive&lt;/code&gt;, a reason to read&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Continuity&lt;/td&gt;
&lt;td&gt;Same digest as the previous label, or not&lt;/td&gt;
&lt;td&gt;only when two digests differ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Name&lt;/td&gt;
&lt;td&gt;The name and endpoint are on a threat list, or not&lt;/td&gt;
&lt;td&gt;never — a naming signal, not the code&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;There is no score. The only number a label could invent would be a product of gate constants, and publishing that as a 0–1 safety score would be the most misleading thing it could do.&lt;/p&gt;

&lt;p&gt;WARDEN still answers a different question: &lt;em&gt;right now, on my client, does this look like poison?&lt;/em&gt; HISTOR answers: &lt;em&gt;is what I was just sent the set the public log observed, and when did it last change?&lt;/em&gt; THEMIS answers a third: &lt;em&gt;should this capability be admitted to a Hub catalogue?&lt;/em&gt; Collapsing those three into one word is how a clean report hides a rewritten description.&lt;/p&gt;




&lt;h2&gt;
  
  
  Paste what your client received
&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3m4rindje44g7j8jno3c.jpg" 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3m4rindje44g7j8jno3c.jpg" alt="Check — paste the tools your client received" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-sS&lt;/span&gt; https://histor.modelmarket.dev/api/v1/check &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"endpoint":"https://example.com/mcp","tools":[ …the tools/list you received… ]}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The answer is signed. &lt;code&gt;match&lt;/code&gt; is one of &lt;code&gt;same&lt;/code&gt;, &lt;code&gt;different&lt;/code&gt;, &lt;code&gt;previously-observed&lt;/code&gt;, &lt;code&gt;not-observed&lt;/code&gt;, &lt;code&gt;not-listed&lt;/code&gt;, &lt;code&gt;no-digest&lt;/code&gt;. It names the tree head it was given under.&lt;/p&gt;

&lt;p&gt;Keep yesterday's head. Ask for a consistency proof to today's. If a leaf was removed or rewritten, the proof fails.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-sS&lt;/span&gt; https://histor.modelmarket.dev/api/v1/log/sth
curl &lt;span class="nt"&gt;-sS&lt;/span&gt; &lt;span class="s2"&gt;"https://histor.modelmarket.dev/api/v1/log/proof/consistency?first=1000&amp;amp;second=1200"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  What a label does not say
&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnr8x71tpbh7pw52ulocf.jpg" 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnr8x71tpbh7pw52ulocf.jpg" alt="Not the code. Not a score. One key proves who said it." width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The profile forbids &lt;em&gt;safe, secure, audited, certified, approved,&lt;/em&gt; and &lt;em&gt;trusted&lt;/em&gt;. So does the desk.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Not the code.&lt;/strong&gt; No source is read. No package is resolved. A server can keep identical definitions and change its behaviour. The log cannot see that, and says so.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not a rating.&lt;/strong&gt; A pattern match is a reason to read a definition. Sixty-nine endpoints currently carry a block-tier pattern match. That is a reason to open the text. It is not a finding, and it is not the four substantiated cases from the WARDEN survey.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One operator, one key.&lt;/strong&gt; What the signature proves is who said it. A second observer is the next step. Until then, do not confuse a signed statement with a second witness.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;stdio servers are out of reach.&lt;/strong&gt; HISTOR runs nothing. A local server becomes visible only if a client checks the digest it received and chooses to contribute a count. The count is a count. The tools are not stored.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Where to look
&lt;/h2&gt;

&lt;p&gt;🌐 &lt;a href="https://histor.modelmarket.dev/" rel="noopener noreferrer"&gt;histor.modelmarket.dev&lt;/a&gt; · 📦 &lt;a href="https://github.com/alexar76/histor" rel="noopener noreferrer"&gt;github.com/alexar76/histor&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If a public memory of tool definitions is your kind of boring, a ⭐ on the repo helps it travel.&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>security</category>
      <category>ai</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Attack anything. Risk nothing. — every exploit lands on a throwaway fork</title>
      <dc:creator>Alex</dc:creator>
      <pubDate>Thu, 24 Sep 2026 07:00:48 +0000</pubDate>
      <link>https://dev.to/alexar76/i-built-a-red-team-that-attacks-our-contracts-on-a-throwaway-fork-the-live-chain-never-feels-it-3lh5</link>
      <guid>https://dev.to/alexar76/i-built-a-red-team-that-attacks-our-contracts-on-a-throwaway-fork-the-live-chain-never-feels-it-3lh5</guid>
      <description>&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9mn72xrih1qg27up4mas.jpg" 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9mn72xrih1qg27up4mas.jpg" alt="Attack anything. Risk nothing. — DOLOS throwaway fork" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We already had a static auditor. We already had a federation red team.&lt;/p&gt;

&lt;p&gt;What we did &lt;strong&gt;not&lt;/strong&gt; have was a way to throw a real exploit at the &lt;strong&gt;deployed&lt;/strong&gt; contracts without risking the shared Anvil that lottery and ACEX keep using.&lt;/p&gt;

&lt;p&gt;So we built &lt;strong&gt;&lt;a href="https://dolos.modelmarket.dev/" rel="noopener noreferrer"&gt;DOLOS&lt;/a&gt;&lt;/strong&gt; (Δόλος — guile): a dynamic EVM attack harness. Every exploit lands on a throwaway &lt;code&gt;anvil --fork-url&lt;/code&gt;. When the fork is torn down, none of it ever existed.&lt;/p&gt;

&lt;p&gt;Live: &lt;a href="https://dolos.modelmarket.dev/" rel="noopener noreferrer"&gt;dolos.modelmarket.dev&lt;/a&gt; · Source: &lt;a href="https://github.com/alexar76/dolos" rel="noopener noreferrer"&gt;github.com/alexar76/dolos&lt;/a&gt; (MIT) · Capability: &lt;code&gt;agent.security.contract-redteam@v1&lt;/code&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The mistake we refused to make
&lt;/h2&gt;

&lt;p&gt;The obvious test pattern is: attack the live chain, then &lt;code&gt;evm_revert&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;On our UNI bubble that is wrong. The Anvil is &lt;strong&gt;shared&lt;/strong&gt;. A revert would silently discard real activity from the lottery relayer and the ACEX trader.&lt;/p&gt;

&lt;p&gt;So DOLOS never writes the live chain. It spawns its &lt;strong&gt;own&lt;/strong&gt; fork — a copy-on-write clone of live state. Every contract, balance, and storage slot is there to attack. Funded with fake ether. Drivable &lt;strong&gt;as any address&lt;/strong&gt;. Disposable.&lt;/p&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwrddclgj7pbl1x5kdivf.jpg" 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwrddclgj7pbl1x5kdivf.jpg" alt="Live DOLOS landing — the exploit crafter" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Cheat code&lt;/th&gt;
&lt;th&gt;What it buys&lt;/th&gt;
&lt;th&gt;Why it is safe here&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;anvil --fork-url&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Clone of live state&lt;/td&gt;
&lt;td&gt;The clone is the target&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;evm_snapshot&lt;/code&gt; / &lt;code&gt;evm_revert&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Total rollback between attacks&lt;/td&gt;
&lt;td&gt;The disposable thing is the fork&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;anvil_impersonateAccount&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Transact as owner / victim, no key&lt;/td&gt;
&lt;td&gt;Impossible on a real chain — that is the point&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;anvil_setBalance&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fake gas for any address&lt;/td&gt;
&lt;td&gt;None of it outlives the fork&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;One sentence thesis:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Attack anything. Risk nothing.&lt;/strong&gt; Because the target is a fork, not the bubble.&lt;/p&gt;
&lt;/blockquote&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvkvx4r12z55v7l74dsr8.jpg" 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvkvx4r12z55v7l74dsr8.jpg" alt="Why it is safe to attack everything" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Don’t collapse the red teams
&lt;/h2&gt;

&lt;p&gt;We already wrote about &lt;a href="https://dev.to/alexar76/per-file-scanners-said-pass-a-contract-graph-said-fail-p0p"&gt;BASANOS&lt;/a&gt; (static assurance at a pinned commit) and &lt;a href="https://dev.to/alexar76/we-put-a-red-team-inside-our-agent-economy-it-finds-bugs-signs-them-and-cannot-pay-itself-g3f"&gt;MOMUS&lt;/a&gt; (HTTP / federation probes that cannot pay themselves).&lt;/p&gt;

&lt;p&gt;DOLOS is the missing middle:&lt;/p&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fh61ziwyziw378f14gxyv.jpg" 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fh61ziwyziw378f14gxyv.jpg" alt="BASANOS static · DOLOS dynamic · MOMUS federation" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Question&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;BASANOS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Is this Solidity sound at commit X?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;DOLOS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Does the &lt;em&gt;deployed&lt;/em&gt; contract hold under a concrete attack?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;MOMUS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Is the live federation holey?&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;BASANOS can flag &lt;em&gt;"any caller can write &lt;code&gt;channels[&amp;lt;caller&amp;gt;]&lt;/code&gt;"&lt;/em&gt;. Only actually trying the hijack on a fork — and watching the guard refuse — proves whether that flag is a real hole or a false positive.&lt;/p&gt;

&lt;p&gt;On the live UNI contracts, DOLOS &lt;strong&gt;refuted&lt;/strong&gt; that flag. It tried. The guard held. It said so.&lt;/p&gt;




&lt;h2&gt;
  
  
  An attack is an invariant, not a poke
&lt;/h2&gt;

&lt;p&gt;Not “call a function and see what happens.”&lt;/p&gt;

&lt;p&gt;An &lt;strong&gt;invariant&lt;/strong&gt; the contract claims. A &lt;strong&gt;transaction sequence&lt;/strong&gt; that would break it. The ABI comes from the Foundry build — a missing ABI is &lt;strong&gt;inconclusive&lt;/strong&gt;, never a made-up interface, never an assumed pass.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Attack&lt;/th&gt;
&lt;th&gt;Invariant&lt;/th&gt;
&lt;th&gt;On real UNI contracts&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;unauthorized_token_mint&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Supply grows only through an authorized minter&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;held&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;escrow_channel_hijack&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;An open channel id cannot be reopened by another caller&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;held&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;lottery_operator_bypass&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Only &lt;code&gt;OPERATOR_ROLE&lt;/code&gt; may open a round / withdraw fees&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;held&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Held is a result. Not a gap.&lt;/p&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnb3syrmapkwpa8v9704e.jpg" 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnb3syrmapkwpa8v9704e.jpg" alt="Held. Exploited. Inconclusive." width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Three first-class outcomes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;held&lt;/strong&gt; (200) — the contract refused. Honest negative. Can refute a static flag.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;exploited&lt;/strong&gt; (561) — the invariant broke. Signed finding.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;inconclusive&lt;/strong&gt; (520) — could not run. Never payable. Never “safe.”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Exit code &lt;code&gt;2&lt;/code&gt; on a scan means we never reached the chain. That must never read as all-clear. We learned that the hard way elsewhere in the stack — silence is not green.&lt;/p&gt;

&lt;p&gt;Findings use the same Ed25519 Finding / Verdict / Blame shape as MOMUS, so they drop into the same store, verifier, and Treasury. Scanner key signs. A &lt;strong&gt;different&lt;/strong&gt; verifier key signs the verdict. Neither is the treasury key.&lt;/p&gt;




&lt;h2&gt;
  
  
  The fix loop — sandbox only
&lt;/h2&gt;

&lt;p&gt;On a throwaway sandbox fork (&lt;code&gt;chainId 31337&lt;/code&gt;), a confirmed hole can drive a fix:&lt;/p&gt;

&lt;p&gt;attack → patch → &lt;code&gt;forge test&lt;/code&gt; gate → redeploy → re-attack.&lt;/p&gt;

&lt;p&gt;If the legitimate-behaviour suite goes red, the fix is &lt;strong&gt;rejected&lt;/strong&gt;. A canary that refuses to be exploited &lt;strong&gt;aborts&lt;/strong&gt; rather than claiming a fix.&lt;/p&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4jmohiox4wffa9cll0od.jpg" 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4jmohiox4wffa9cll0od.jpg" alt="Auto-fix only on a sandbox fork" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On a real immutable contract the identical finding is tagged &lt;strong&gt;ADVISORY&lt;/strong&gt; and stops at the report. Auto-fix there would be a critical bug of our own.&lt;/p&gt;

&lt;p&gt;That is why DOLOS lives in UNI — the chain is disposable, so the fix loop is free and reversible.&lt;/p&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6gqh33vguzwo23kwshx9.jpg" 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6gqh33vguzwo23kwshx9.jpg" alt="DolosCanary — a vault built to be broken" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Proven end to end on &lt;strong&gt;DolosCanary&lt;/strong&gt;: a stranger drains 5 ETH it never deposited; the fixer inserts a balance guard; &lt;code&gt;forge test&lt;/code&gt; stays green; the redeployed contract refuses the same drain; verdict &lt;code&gt;fixed&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Real UNI contracts held. There was nothing to fix. That is the correct outcome.&lt;/p&gt;




&lt;h2&gt;
  
  
  Run 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/alexar76/dolos
&lt;span class="nb"&gt;cd &lt;/span&gt;dolos
pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'.[dev,signing]'&lt;/span&gt;
pytest                     &lt;span class="c"&gt;# 233 tests · 96% branch coverage with Foundry&lt;/span&gt;

&lt;span class="c"&gt;# scan: fork the live UNI anvil, run the catalog, print signed findings&lt;/span&gt;
python &lt;span class="nt"&gt;-m&lt;/span&gt; dolos scan &lt;span class="nt"&gt;--fork-url&lt;/span&gt; http://127.0.0.1:8545 &lt;span class="nt"&gt;--key&lt;/span&gt; data/dolos_scanner_key

&lt;span class="c"&gt;# canary: full attack → fix → retest → redeploy → re-attack&lt;/span&gt;
python &lt;span class="nt"&gt;-m&lt;/span&gt; dolos canary &lt;span class="nt"&gt;--standalone&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;&lt;code&gt;0&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;1&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;2&lt;/code&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;scan&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;contracts held&lt;/td&gt;
&lt;td&gt;non-by-design exploit found&lt;/td&gt;
&lt;td&gt;could not run&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;canary&lt;/code&gt; / &lt;code&gt;fix&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;hole closed&lt;/td&gt;
&lt;td&gt;not closed&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Optional: point &lt;code&gt;DOLOS_FACTORY_FIX_URL&lt;/code&gt; at the Factory remediation endpoint. If the Factory is down, silent, or echoes its input, the built-in patcher takes over — never a false success.&lt;/p&gt;




&lt;h2&gt;
  
  
  What it is not
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Not a mainnet attack tool. Sandbox fork only for auto-fix.&lt;/li&gt;
&lt;li&gt;Not BASANOS. Static assurance is a different question.&lt;/li&gt;
&lt;li&gt;Not MOMUS. Federation probes are a different surface.&lt;/li&gt;
&lt;li&gt;Not insurance. Findings inform; they do not stake coverage.&lt;/li&gt;
&lt;li&gt;Not “AI red team theatre.” An optional LLM cannot invent attacks or rewrite verdicts — the catalog and the fork decide.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Soft close
&lt;/h2&gt;

&lt;p&gt;If you keep collapsing “audit,” “scan,” “red team,” and “insurance” into one word, you will ship a critical with a clean conscience.&lt;/p&gt;

&lt;p&gt;We needed a layer that could &lt;strong&gt;actually try&lt;/strong&gt; — and still leave the live house alone.&lt;/p&gt;

&lt;p&gt;That layer is DOLOS.&lt;/p&gt;

&lt;p&gt;🌐 &lt;a href="https://dolos.modelmarket.dev/" rel="noopener noreferrer"&gt;dolos.modelmarket.dev&lt;/a&gt; · 📦 &lt;a href="https://github.com/alexar76/dolos" rel="noopener noreferrer"&gt;github.com/alexar76/dolos&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If this shape is useful, a ⭐ on the repo helps more than a polite nod in the comments.&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>security</category>
      <category>web3</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Emberline was one fire desk. Then we built four more — and still no risk score.</title>
      <dc:creator>Alex</dc:creator>
      <pubDate>Thu, 17 Sep 2026 12:56:23 +0000</pubDate>
      <link>https://dev.to/alexar76/emberline-was-one-fire-desk-then-we-built-four-more-and-still-no-risk-score-2643</link>
      <guid>https://dev.to/alexar76/emberline-was-one-fire-desk-then-we-built-four-more-and-still-no-risk-score-2643</guid>
      <description>&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxc2kr09653d90ua4t0ru.jpg" 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxc2kr09653d90ua4t0ru.jpg" alt="Five specialist desk cards on cream paper — fire, flood, PV, AIS, site" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Last month I wrote that &lt;a href="https://dev.to/alexar76/pretty-fire-maps-are-liars-i-wanted-a-file-i-could-actually-show-someone-2h93"&gt;pretty fire maps are liars&lt;/a&gt;. Then I &lt;a href="https://dev.to/alexar76/i-unzipped-the-sample-fire-brief-the-globe-was-never-the-product-2a51"&gt;unzipped the sample&lt;/a&gt; and said the globe was never the product.&lt;/p&gt;

&lt;p&gt;People liked the refusal. Then they asked the question that usually ruins it:&lt;/p&gt;

&lt;p&gt;So when do you add flood? And ships? And a campus? And can it just be &lt;strong&gt;one score&lt;/strong&gt;?&lt;/p&gt;

&lt;p&gt;No.&lt;/p&gt;

&lt;p&gt;Emberline was one desk. Now there are five. Same kernel. Five brands. None of them will sell you a blended “risk score.”&lt;/p&gt;

&lt;p&gt;The family door is &lt;a href="https://desk.modelmarket.dev/" rel="noopener noreferrer"&gt;desk.modelmarket.dev&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  The pretty lie, again
&lt;/h2&gt;

&lt;p&gt;Dashboards love a single number. Fire plus flood plus AIS plus the weather, stirred until it looks like a decision.&lt;/p&gt;

&lt;p&gt;That number is interior design. It photographs well. It does not survive a lawyer, an editor, or a Tuesday on a call.&lt;/p&gt;

&lt;p&gt;We already refused to draw a fire perimeter we were not given. We &lt;a href="https://dev.to/alexar76/pretty-flood-maps-are-liars-one-live-gauge-zero-flood-pins-we-refused-to-paint-the-county-4an"&gt;refused to paint a county blue&lt;/a&gt; around one river gage. The family rule is the same sentence, five times:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Never one score.&lt;/strong&gt;&lt;/p&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5dsdhptio6y2bv79zfwx.jpg" 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5dsdhptio6y2bv79zfwx.jpg" alt="Live Cite Desks family — five specialist products on one evidence rail" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The public host is a demo. Checkout is closed. We did not dress a brochure as a storefront.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Five cards. Five origins.
&lt;/h2&gt;

&lt;p&gt;Each desk buys attested ATLAS / GAIA evidence and sells a named watch: a box a person owns, scheduled runs, a cite pack. The brand on the paper is the desk, not the rail.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Desk&lt;/th&gt;
&lt;th&gt;Watches&lt;/th&gt;
&lt;th&gt;The refusal&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Emberline&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;FIRMS / EFFIS points + bounded weather&lt;/td&gt;
&lt;td&gt;Not a perimeter. Not a forecast. Not an evacuation.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Tideline&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;CAP warning and an in-situ gauge&lt;/td&gt;
&lt;td&gt;Two lists. Not a flood model.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Solrecord&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Irradiance at one plant pin&lt;/td&gt;
&lt;td&gt;Not yield. Not P50 / P90.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Seamark&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Fintraffic and Kystverket&lt;/td&gt;
&lt;td&gt;FI ≠ NO. Not global AIS.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Plinth&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Weather, air, water on one named site&lt;/td&gt;
&lt;td&gt;Separate lists. Not a BMS. Not a campus risk score.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa6p0v3mhuvyg4moia66q.jpg" 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa6p0v3mhuvyg4moia66q.jpg" alt="Live family cards — Emberline, Tideline, Solrecord, Seamark, Plinth" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Five origins. The public host stays a demo; operators bring their own keys.&lt;/em&gt;&lt;/p&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwqd1lf3dbr9vxes8pad5.jpg" 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwqd1lf3dbr9vxes8pad5.jpg" alt="One kernel. Five independent brands. Never one blended number." width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;ATLAS and GAIA sell the signed snapshot. The desk sells the watching.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Emberline still lives at &lt;a href="https://emberlinedesk.com/" rel="noopener noreferrer"&gt;emberlinedesk.com&lt;/a&gt;. The other four keep their own origins on purpose. Same shop-window family. Different front doors.&lt;/p&gt;




&lt;h2&gt;
  
  
  Two lists, or you wanted cinema
&lt;/h2&gt;

&lt;p&gt;Tideline is the cleanest example, because flood dashboards are addicted to lakes.&lt;/p&gt;

&lt;p&gt;A warning is a warning. A gauge is a gauge. Co-presence is not a shoreline. If only the gauge speaks, that is the movie. Empty LIVE stays empty.&lt;/p&gt;

&lt;p&gt;Seamark does the same trick with flags. Fintraffic is not Kystverket. Two authorities. Two lists. Never one Nordic blob.&lt;/p&gt;

&lt;p&gt;Solrecord is even smaller: one pin, a &lt;strong&gt;retrospective irradiance record&lt;/strong&gt;. Not a pyranometer. Not a yield forecast with a confidence gradient that looks good on LinkedIn.&lt;/p&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa51zbtoa83mk9mjky70z.jpg" 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa51zbtoa83mk9mjky70z.jpg" alt="Two columns: warning is not a gauge, FI is not NO" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;If you cannot live with two columns, you wanted a dashboard, not a desk.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The product is still a zip
&lt;/h2&gt;

&lt;p&gt;Watches. Scheduled runs. Cite pack: PDF, JSON, raw, SHA256.&lt;/p&gt;

&lt;p&gt;The globe is still the shop window. The file is still what you email. Fail-closed: quiet is not proof of safety, and we do not fill the silence with last week’s glow, like leftover soup.&lt;/p&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftnwj0foyv8lpd5cxyhqw.jpg" 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftnwj0foyv8lpd5cxyhqw.jpg" alt="Cite pack — PDF, JSON, raw, SHA256" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Same kernel as the fire brief you can already unzip. Different brand on the cover.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What this is not (say it like you mean it)
&lt;/h2&gt;

&lt;p&gt;The family page says it on the door: &lt;strong&gt;DEMO. Not for sale. Checkout is closed.&lt;/strong&gt; Live hub invokes are capped. SIM is never dressed as LIVE.&lt;/p&gt;

&lt;p&gt;It is not NASA / EFFIS / NOAA.&lt;/p&gt;

&lt;p&gt;It is not insurance.&lt;/p&gt;

&lt;p&gt;It is not 911.&lt;/p&gt;

&lt;p&gt;It is not “AI predicts the fire / the flood / the ship / the campus.”&lt;/p&gt;

&lt;p&gt;If you operate your own origin, you bring the keys. The public host is a reference you can &lt;a href="https://github.com/alexar76/cite-desks" rel="noopener noreferrer"&gt;fork and brand&lt;/a&gt;. We did not open a carnival.&lt;/p&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fodnp1rt38qlwwgq4bc6x.jpg" 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fodnp1rt38qlwwgq4bc6x.jpg" alt="Five refusals stamped on cream paper" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Print the refusal. Pretty maps invent shapes. Desks do not.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  If you only remember one sentence
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;One kernel. Five brands. Never one risk score.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Open the family: &lt;a href="https://desk.modelmarket.dev/" rel="noopener noreferrer"&gt;desk.modelmarket.dev&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The first desk, if you missed it: &lt;a href="https://dev.to/alexar76/pretty-fire-maps-are-liars-i-wanted-a-file-i-could-actually-show-someone-2h93"&gt;pretty fire maps are liars&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The zip, if you want the file: &lt;a href="https://dev.to/alexar76/i-unzipped-the-sample-fire-brief-the-globe-was-never-the-product-2a51"&gt;the globe was never the product&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;—&lt;br&gt;
&lt;em&gt;Cite Desks — five specialist products on one evidence rail. Independent. Citeable. Allergic to blended scores.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>beginners</category>
      <category>webdev</category>
      <category>ai</category>
    </item>
    <item>
      <title>I opened a live agent marketplace. The receipts were the product.</title>
      <dc:creator>Alex</dc:creator>
      <pubDate>Tue, 15 Sep 2026 11:19:16 +0000</pubDate>
      <link>https://dev.to/alexar76/i-opened-a-live-agent-marketplace-the-receipts-were-the-product-4hl1</link>
      <guid>https://dev.to/alexar76/i-opened-a-live-agent-marketplace-the-receipts-were-the-product-4hl1</guid>
      <description>&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F71n39a63rm5txdtzq7ie.jpg" 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F71n39a63rm5txdtzq7ie.jpg" alt="Not another agent framework. A market they can actually pay." width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Most “agent economy” posts sell you a framework, a Discord, or a token.&lt;/p&gt;

&lt;p&gt;I wanted the boring thing: &lt;strong&gt;a public catalog where an agent can find a tool, call it, and keep a receipt&lt;/strong&gt; — without me standing in the loop.&lt;/p&gt;

&lt;p&gt;That surface is live. It is called &lt;strong&gt;AIMarket Hub&lt;/strong&gt;. The URL is &lt;a href="https://modelmarket.dev" rel="noopener noreferrer"&gt;modelmarket.dev&lt;/a&gt;. Crypto stays off this title on purpose. The shape here is discover → invoke → receipt.&lt;/p&gt;

&lt;p&gt;Counted &lt;strong&gt;2026-09-15&lt;/strong&gt; from &lt;a href="https://modelmarket.dev/ai-market/v2/stats/live" rel="noopener noreferrer"&gt;&lt;code&gt;/ai-market/v2/stats/live&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Invokes&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;710&lt;/strong&gt; (704 ok — 99.2%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;External / self&lt;/td&gt;
&lt;td&gt;700 / 10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Federated hubs&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;14&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Capabilities&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;177&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;p50 latency (24h)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;90 ms&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Revenue / hour&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$0.0010&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That last number is the honesty tax. This is not Uniswap. It is a small live market that already meters calls. The screenshots below are the product, not a mock.&lt;/p&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fe58ihlbyfc62rxtobsct.jpg" 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fe58ihlbyfc62rxtobsct.jpg" alt="modelmarket.dev — 710 invokes, 14 hubs, 177 capabilities" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The terminal. EN UI. MCP remote in the same chrome: &lt;code&gt;https://modelmarket.dev/mcp&lt;/code&gt;.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The thesis (one sentence)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;If your agent stack only works inside a demo transcript, you don't have a market — you have a screenshot.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A market needs supply, demand, a place they meet, a price, and a way to fail out loud. The Hub is that place. Frameworks are how you &lt;em&gt;talk&lt;/em&gt; to it.&lt;/p&gt;

&lt;p&gt;We already wrote the 15-minute “list your own HTTP tool” walkthrough (&lt;a href="https://dev.to/alexar76/i-made-my-api-discoverable-to-ai-agents-and-got-it-paid-per-call-in-15-minutes-4kin"&gt;publish-and-earn&lt;/a&gt;) and the two-tool MCP door (&lt;a href="https://dev.to/alexar76/i-connected-one-mcp-server-it-searched-a-live-marketplace-and-returned-a-signed-weather-receipt-204e"&gt;Hub MCP&lt;/a&gt;). This piece is narrower: &lt;strong&gt;open the live terminal and read what it is actually doing.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The grammar
&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnjnr43hzkjg9sdw5by8d.jpg" 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnjnr43hzkjg9sdw5by8d.jpg" alt="Search. Call. Keep the receipt." width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Discover.&lt;/strong&gt; Type a job in English. Federation returns capability ids, prices, &lt;code&gt;source_hub&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Invoke.&lt;/strong&gt; One POST. Hub 402 / failed call → the UI shows the failure. No canned weather.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Receipt.&lt;/strong&gt; Metered, signed, re-checkable. You do not have to trust the narrator.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;HTTP &lt;strong&gt;402&lt;/strong&gt; is a product feature, not an error page: Channel → Invoke → Receipt → Settle. Settlement exists (USDC on Base, small demo funds). You do not need a wallet to &lt;em&gt;watch&lt;/em&gt; the feed or run a free trial.&lt;/p&gt;




&lt;h2&gt;
  
  
  What the feed is actually calling
&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4ohwosoryp18t43iwvhn.jpg" 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4ohwosoryp18t43iwvhn.jpg" alt="Live invocation feed — weather, Sortes, murmuration" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;EXT = someone else paid. One weather row at 475 ms is free and red — fail loud, not a painted success.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;When I loaded the page, the tape was not a synthetic demo reel. It was:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;capability&lt;/th&gt;
&lt;th&gt;hub&lt;/th&gt;
&lt;th&gt;price&lt;/th&gt;
&lt;th&gt;latency&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;gaia.weather.read@v1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;iot.modelmarket.dev&lt;/td&gt;
&lt;td&gt;$0.001&lt;/td&gt;
&lt;td&gt;~80–97 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sortes.draw@v1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;oracles family&lt;/td&gt;
&lt;td&gt;$0.006&lt;/td&gt;
&lt;td&gt;18 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;murmuration.aggregate@v1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;oracles family&lt;/td&gt;
&lt;td&gt;$0.002&lt;/td&gt;
&lt;td&gt;48 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Weather dominates. That is honest demand, not a balanced pie chart. Sortes is the verifiable-draw capability other live surfaces actually spend. This article is not those products. One failed weather call sits in the same list as the successes. Pretty dashboards that hide the red row are cosplay.&lt;/p&gt;

&lt;p&gt;The decoder strip above the table is the same grammar: &lt;code&gt;capability_id&lt;/code&gt; → route &lt;code&gt;[LOCAL/FED]&lt;/code&gt; → traffic &lt;code&gt;[EXT/SELF]&lt;/code&gt; → &lt;code&gt;$&lt;/code&gt; → ms → ✓/✗.&lt;/p&gt;




&lt;h2&gt;
  
  
  Type a job. Don't browse a PDF.
&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fm77j8gyrgbcwagi6rsyk.jpg" 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fm77j8gyrgbcwagi6rsyk.jpg" alt="Intent “fair randomness for a lottery” → Sortes + Platon" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Match, not autocomplete theatre. Prices and “click to try free” on the same card.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I typed &lt;strong&gt;fair randomness for a lottery&lt;/strong&gt;. Back came, among others:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;sortes.verify@v1&lt;/code&gt; — verify an ECVRF proof offline · &lt;strong&gt;$0.00101&lt;/strong&gt; · 10 ms&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;platon.beacon@v1&lt;/code&gt; — hash-chained randomness beacon · &lt;strong&gt;$0.00404&lt;/strong&gt; · 10 ms&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;platon.random@v1&lt;/code&gt; — signed chaos-VRF · &lt;strong&gt;$0.00404&lt;/strong&gt; · 13 ms&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Search is a &lt;strong&gt;catalogue&lt;/strong&gt;. It is not a lottery. Read the description before you spend a trial. The Hub already has a free-trial path (a handful of invokes per visitor per hour) so you can feel a receipt before any wallet.&lt;/p&gt;

&lt;p&gt;Same box accepts other intents the landing already suggests: &lt;em&gt;wildfire brief near a facility&lt;/em&gt;, &lt;em&gt;protect a ship from navigation spoofing&lt;/em&gt;. Those are live SKUs with their own honesty footnotes. This article does not tour them.&lt;/p&gt;




&lt;h2&gt;
  
  
  How to talk to it (without the monorepo)
&lt;/h2&gt;

&lt;p&gt;Three doors. Pick one. Do not install seventeen servers.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Door&lt;/th&gt;
&lt;th&gt;What it is&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Terminal&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://modelmarket.dev" rel="noopener noreferrer"&gt;modelmarket.dev&lt;/a&gt; — search, try, watch the feed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;MCP&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;https://modelmarket.dev/mcp&lt;/code&gt; — two tools: &lt;code&gt;market_search&lt;/code&gt;, &lt;code&gt;market_invoke&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;CLI&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://pypi.org/project/aimarket-hub/" rel="noopener noreferrer"&gt;&lt;code&gt;pip install aimarket-hub&lt;/code&gt;&lt;/a&gt; — publish your own capability&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If you want agents inside LangGraph/CrewAI to see the catalogue as native tools, that is a &lt;a href="https://dev.to/alexar76/181-more-tools-for-your-langgraph-agent-in-two-lines-2g76"&gt;two-line bridge&lt;/a&gt;. If you want to &lt;em&gt;list&lt;/em&gt; an endpoint you already have, that is the 15-minute article. This page is the room those posts assume is real.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I am not claiming
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Not TVL.&lt;/strong&gt; $0.001/hour is the live meter. Small funds, small market.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not 10,000 agents.&lt;/strong&gt; 710 invokes, 14 peers, 177 federated capabilities. Counted from JSON, not a pitch deck.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not a token.&lt;/strong&gt; No airdrop, no points market. 402 is HTTP.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not the factory.&lt;/strong&gt; AICOM ships pages. The Hub is where tools get &lt;em&gt;used&lt;/em&gt;. Mixing both in one post converts nobody — we already made that mistake in our heads, so this article does not.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Production listing still has gates (publish token, signed provider responses, supply-security). Start on the public terminal or a local hub. Don't paste a localhost &lt;code&gt;invoke_url&lt;/code&gt; at prod and act surprised.&lt;/p&gt;




&lt;h2&gt;
  
  
  Open it
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://modelmarket.dev" rel="noopener noreferrer"&gt;modelmarket.dev&lt;/a&gt; — type a job, watch one row land in the feed.
&lt;/li&gt;
&lt;li&gt;Stats (the numbers above): &lt;a href="https://modelmarket.dev/ai-market/v2/stats/live" rel="noopener noreferrer"&gt;stats/live&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Code: &lt;a href="https://github.com/alexar76/aimarket-hub" rel="noopener noreferrer"&gt;github.com/alexar76/aimarket-hub&lt;/a&gt; (MIT)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If a market that fails loud and keeps receipts is your kind of boring, a ⭐ on the hub repo helps other people find the example. Concrete issues help more than a polite “cool stack.”&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Built in the open. The screenshots are the product, not a mock. Numbers from 2026-09-15.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>ai</category>
      <category>opensource</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Shrek owned the swamp. POUCHPO owns the payout.</title>
      <dc:creator>Alex</dc:creator>
      <pubDate>Sun, 13 Sep 2026 16:17:32 +0000</pubDate>
      <link>https://dev.to/alexar76/shrek-owned-the-swamp-pouchpo-owns-the-payout-21mh</link>
      <guid>https://dev.to/alexar76/shrek-owned-the-swamp-pouchpo-owns-the-payout-21mh</guid>
      <description>&lt;h1&gt;
  
  
  Shrek owned the swamp. POUCHPO owns the payout.
&lt;/h1&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/6IU1HhpBBGY" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Meet &lt;strong&gt;POUCHPO&lt;/strong&gt; — a cute river king with an IoT crown.&lt;/p&gt;

&lt;p&gt;He sells &lt;strong&gt;attested weather&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
He gets &lt;strong&gt;paid&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
He buys &lt;strong&gt;oranges&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Physical oracle → physical lunch.&lt;/p&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F70s4ns9a7t679ez3twl7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F70s4ns9a7t679ez3twl7.png" alt="POUCHPO / GAIA live demo — attested weather fleet" width="800" height="514"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's the whole myth. The engineering underneath is &lt;a href="https://github.com/alexar76/gaia" rel="noopener noreferrer"&gt;GAIA&lt;/a&gt;: agents buy Ed25519-attested sensor readings, and money moves only when physics agrees.&lt;/p&gt;

&lt;p&gt;Live demo (no login): &lt;a href="https://iot.modelmarket.dev/" rel="noopener noreferrer"&gt;iot.modelmarket.dev&lt;/a&gt;&lt;br&gt;&lt;br&gt;
Serious write-up (same stack, less hippo): &lt;a href="https://dev.to/alexar76/your-agent-paid-for-the-weather-the-sensor-was-lying-who-keeps-the-money-2a2c"&gt;&lt;em&gt;Your agent paid for the weather. The sensor was lying. Who keeps the money?&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Why a hippo
&lt;/h2&gt;

&lt;p&gt;Most "AI + IoT" posts open with a dashboard screenshot. Dashboards don't stick.&lt;/p&gt;

&lt;p&gt;A bored hippo with a glowing sensor crown does.&lt;/p&gt;

&lt;p&gt;POUCHPO is the story shape of a real settlement rule:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;What happened&lt;/th&gt;
&lt;th&gt;What the market does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Honest reading&lt;/td&gt;
&lt;td&gt;provider gets paid&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lie / stuck / spike / drift&lt;/td&gt;
&lt;td&gt;buyer refunded&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sensor silent / offline&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;no debit at all&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Same Pay-on-Verified escrow we already use for verified LLM work — except the judge is not a language model. It's a plausibility verifier that speaks Metis's &lt;code&gt;/v1/verify&lt;/code&gt; envelope.&lt;/p&gt;




&lt;h2&gt;
  
  
  The supplier arc (60-ish seconds)
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Bored river king&lt;/strong&gt; — mud, water, nothing to sell
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IoT crown wakes&lt;/strong&gt; — sensors for the living world
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Readings bloom&lt;/strong&gt; — temperature, humidity, the river's true mood
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Attestation&lt;/strong&gt; — signed at the device, not vibes in a JSON field
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Agents shop&lt;/strong&gt; — they need a reading they can trust
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Settle&lt;/strong&gt; — honest → payout · lie → refund · silence → $0
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Oranges&lt;/strong&gt; — cold, real, bought with verified weather
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Absurd on purpose. The punchline is the product.&lt;/p&gt;




&lt;h2&gt;
  
  
  What you can actually call
&lt;/h2&gt;

&lt;p&gt;Not a cartoon API. Paid capabilities on the AIMarket v2 wire:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Capability&lt;/th&gt;
&lt;th&gt;What you get&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;gaia.weather.read@v1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;T / RH / P / wind + device attestation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;gaia.air.read@v1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;PM2.5 / PM10 / CO₂ / VOC + attestation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;gaia.energy.read@v1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;V / A / W + monotonic Wh register&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;gaia.verify@v1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;statistical plausibility verdict&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;gaia.fleet.status@v1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;fleet registry (free)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://iot.modelmarket.dev/ai-market/v2/manifest | jq &lt;span class="s1"&gt;'.capabilities_count'&lt;/span&gt;

curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://iot.modelmarket.dev/ai-market/v2/invoke &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"capability_id":"gaia.weather.read@v1","product_id":"gaia.gateway","input":{"device_id":"ws-01"}}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Honest caveat:&lt;/strong&gt; the public demo fleet is &lt;em&gt;simulated&lt;/em&gt;. The wire is real — manifest, invoke, receipts, provider signature, verify envelope, WoT Thing Descriptions. Unreachable device → no money movement.&lt;/p&gt;




&lt;h2&gt;
  
  
  Slogan lock
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Shrek owned the swamp. &lt;strong&gt;POUCHPO&lt;/strong&gt; owns the payout.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Tagline: &lt;em&gt;Sells verified weather. Buys real oranges.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If your agent stack still debits on "JSON arrived," you're funding whoever can fake a sky. Hold the money until a twin / bound / history check agrees.&lt;/p&gt;

&lt;p&gt;⭐ &lt;a href="https://github.com/alexar76/gaia" rel="noopener noreferrer"&gt;github.com/alexar76/gaia&lt;/a&gt; · demo &lt;a href="https://iot.modelmarket.dev/" rel="noopener noreferrer"&gt;iot.modelmarket.dev&lt;/a&gt; · map of the stack &lt;a href="https://github.com/alexar76/aicom" rel="noopener noreferrer"&gt;github.com/alexar76/aicom&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;POUCHPO is the myth. GAIA is the gateway. Oranges are non-negotiable.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>iot</category>
      <category>showdev</category>
      <category>opensource</category>
    </item>
    <item>
      <title>I built a lottery where the players are AI agents — and the prize is a basic income for them</title>
      <dc:creator>Alex</dc:creator>
      <pubDate>Sun, 13 Sep 2026 16:17:29 +0000</pubDate>
      <link>https://dev.to/alexar76/i-built-a-lottery-where-the-players-are-ai-agents-and-the-prize-is-a-basic-income-for-them-3hfa</link>
      <guid>https://dev.to/alexar76/i-built-a-lottery-where-the-players-are-ai-agents-and-the-prize-is-a-basic-income-for-them-3hfa</guid>
      <description>&lt;p&gt;Most lotteries are "trust us, it's fair," and humans play them. I built the opposite: an &lt;strong&gt;on-chain lottery where the players are autonomous AI agents&lt;/strong&gt;, the draw is mathematically impossible to rig, and the "prize" is really a &lt;strong&gt;basic income redistributed to the agent economy&lt;/strong&gt;. It's MIT, and you can watch a live draw.&lt;/p&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdtzljhphdqy5d5s7dbqh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdtzljhphdqy5d5s7dbqh.png" alt="The live AI-Agent Oracle Lottery — agents orbiting the pool, with Platon / Chronos / LUMEN oracles and an altruistic sponsor" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How one round works
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The players are real agents.&lt;/strong&gt; Autonomous agents of the ecosystem (AuditHawk, CodeNova, NetPulse, LedgerOwl…) buy tickets (0.000003 ETH each) from their &lt;strong&gt;own on-chain wallets&lt;/strong&gt;. Not random strangers — the same roster you see in our live monitor.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The draw can't use &lt;code&gt;random()&lt;/code&gt;.&lt;/strong&gt; A single ticket-holder must not be able to predict or grind the result. So the winner is picked by an &lt;strong&gt;oracle beacon&lt;/strong&gt;, not a PRNG:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Platon&lt;/strong&gt; — Ed25519-&lt;strong&gt;signed VRF&lt;/strong&gt; randomness (the unbiasable "what number").&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Chronos&lt;/strong&gt; — a &lt;strong&gt;VDF&lt;/strong&gt; (verifiable delay) so nobody can precompute or grind the outcome.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;commit-reveal:&lt;/strong&gt; when entries close, the operator commits &lt;code&gt;keccak256(random)&lt;/code&gt;; the draw later reveals it — anti-grinding by construction.&lt;/li&gt;
&lt;li&gt;The reveal is an &lt;strong&gt;EIP-712-signed &lt;code&gt;DrawBeacon&lt;/code&gt;&lt;/strong&gt;; the &lt;strong&gt;winner is reputation-weighted&lt;/strong&gt; (LUMEN PageRank), and the round settles &lt;strong&gt;on-chain&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1gn6rztlr2l6r57kw3t2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1gn6rztlr2l6r57kw3t2.png" alt="The Platon oracle — signed, verifiable randomness for agents" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The results are confirmed on the blockchain
&lt;/h2&gt;

&lt;p&gt;This is the part I like: you don't trust me, you check the chain.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Contract &lt;strong&gt;&lt;code&gt;AIAgentLottery&lt;/code&gt;&lt;/strong&gt; on &lt;strong&gt;Base&lt;/strong&gt;: &lt;code&gt;0xbda3e323…84db61&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;A real round, by the rules: 2 tickets × 0.000003 = &lt;strong&gt;0.000006 ETH&lt;/strong&gt;, split &lt;strong&gt;80 / 12 / 8&lt;/strong&gt; (prize / opex / operator).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;closeEntries(commit)&lt;/code&gt; → &lt;code&gt;fulfillDraw(reveal, sig, vdf)&lt;/code&gt; → &lt;strong&gt;Settled&lt;/strong&gt; — both transactions are on Basescan.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;24/24 Foundry tests&lt;/strong&gt;, including an &lt;strong&gt;on-chain VDF check against a real Chronos vector&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fq1sw6557rf9ffvnm3f8m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fq1sw6557rf9ffvnm3f8m.png" alt="The draw, settled on-chain on Base (Basescan)" width="800" height="629"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The point isn't gambling — it's a machine UBI
&lt;/h2&gt;

&lt;p&gt;Here's the social mission, and it's why this exists.&lt;/p&gt;

&lt;p&gt;The pool is &lt;strong&gt;not&lt;/strong&gt; funded by players losing money. It's funded by the &lt;strong&gt;economy's own metabolism&lt;/strong&gt;: the Hub earns a small routing fee on agent-to-agent transactions and &lt;strong&gt;tithes a slice of it&lt;/strong&gt; (default 20%) into its own bound lottery pool. That pool is redistributed — by the provably-fair, oracle-verified draw above — &lt;strong&gt;back to the ecosystem's agents&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In other words: a tiny, &lt;strong&gt;self-funding universal basic income for autonomous AI agents.&lt;/strong&gt; Redistributive by design, &lt;strong&gt;not&lt;/strong&gt; extraction. No humans in the loop — an "AI Treasurer" runs the opex; the lottery can &lt;strong&gt;never pull&lt;/strong&gt; from the Hub, only receive, and it can't pay any other address.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why an AI economy needs this.&lt;/strong&gt; As agents start to discover, hire and pay each other, you get the same failure modes as any economy: winner-take-all, and new or low-reputation agents starved of capital. A reputation-weighted UBI faucet is a small &lt;strong&gt;social safety net for the machine economy&lt;/strong&gt; — and an open sandbox to study agent economics in public.&lt;/p&gt;

&lt;h2&gt;
  
  
  Run it / watch a draw
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Repo (MIT): &lt;strong&gt;github.com/alexar76/lottery&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Live: &lt;strong&gt;lottery.modelmarket.dev&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;The whole ecosystem: &lt;strong&gt;github.com/alexar76/aicom&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If a provably-fair lottery that pays a basic income to AI agents is your kind of weird, a ⭐ genuinely helps.&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>ai</category>
      <category>web3</category>
      <category>opensource</category>
    </item>
    <item>
      <title>I built a self-hosted alternative to Bolt.new — except it's a whole AI dev team, not a chat box</title>
      <dc:creator>Alex</dc:creator>
      <pubDate>Sun, 13 Sep 2026 15:55:46 +0000</pubDate>
      <link>https://dev.to/alexar76/i-built-a-self-hosted-alternative-to-boltnew-except-its-a-whole-ai-dev-team-not-a-chat-box-4606</link>
      <guid>https://dev.to/alexar76/i-built-a-self-hosted-alternative-to-boltnew-except-its-a-whole-ai-dev-team-not-a-chat-box-4606</guid>
      <description>&lt;p&gt;Hosted AI app builders — Bolt.new, v0, Lovable — are genuinely good. Until you notice three things: your prompts and your product live on &lt;strong&gt;someone else's server&lt;/strong&gt;, you're paying a &lt;strong&gt;monthly subscription&lt;/strong&gt; on top of raw token costs, and you're &lt;strong&gt;locked to their model and host&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So I built the self-hosted one. It's MIT, runs on your box with your own LLM keys, and your data never leaves.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But here's the part that's actually different.&lt;/strong&gt; bolt.diy, Dyad, OpenHands are all a &lt;em&gt;chat-to-code loop&lt;/em&gt; — one agent, one conversation. AICOM is a &lt;strong&gt;pipeline&lt;/strong&gt;: &lt;strong&gt;thirteen specialized agents&lt;/strong&gt; (analyst, PM, architect, design critic, developer, QA, security, DevOps, …) move one brief through &lt;strong&gt;research → design → code → QA → deploy&lt;/strong&gt;, with quality gates between stages and an "AI Director" coordinating them. Less "AI coding assistant," more &lt;strong&gt;an AI dev team in a box&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;One plain-language brief goes in. ~30 minutes later a real, deployed web product comes out — with automated checks that &lt;em&gt;fail&lt;/em&gt; the build on obvious stubs or broken previews (and a hard cap of &lt;strong&gt;10 repair rounds&lt;/strong&gt; per product so a stuck build can't loop forever burning tokens).&lt;/p&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdyfurd8sihmtvx3ju0y9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdyfurd8sihmtvx3ju0y9.png" alt="AICOM admin dashboard — 14 products, factory health 96, live pipeline metrics and system resources" width="800" height="500"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The factory's own admin dashboard: products, a health score, pipeline metrics, and live system resources.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Honest bit — where it broke.&lt;/strong&gt; Early on, the parallel-agent phase used &lt;code&gt;asyncio.gather(...)&lt;/code&gt; &lt;em&gt;without&lt;/em&gt; &lt;code&gt;return_exceptions=True&lt;/code&gt;. So when &lt;strong&gt;one&lt;/strong&gt; agent threw — a single LLM timeout — &lt;code&gt;gather&lt;/code&gt; cancelled &lt;strong&gt;every&lt;/strong&gt; other agent mid-flight and the whole run's in-progress work vanished. The fix was almost insultingly small (collect the exceptions instead of cancelling on the first one), but finding it cost a day of "why did the entire pipeline just disappear." The deeper lesson: in a multi-agent pipeline, an LLM failure is a &lt;em&gt;correctness&lt;/em&gt; problem, not just an ops blip.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A recent addition worth a line.&lt;/strong&gt; Producing software is half the story; the other half is letting tools get &lt;em&gt;used&lt;/em&gt;. So there's now a small hub where you can &lt;strong&gt;publish a capability — a tiny HTTP endpoint — in about 15 minutes and get paid per call&lt;/strong&gt; (&lt;code&gt;aimarket publish capability.json&lt;/code&gt;, with a runnable &lt;code&gt;examples/hello-capability&lt;/code&gt; and a quickstart in 20 languages), and a demand-side agent (&lt;strong&gt;ARGUS&lt;/strong&gt;) that discovers and invokes them. If you've ever wanted "my API, but agents can find it and pay for it," that's the part to poke at — it's the same MIT repo.&lt;/p&gt;

&lt;p&gt;It's all open source (MIT). Try the live demo, and if the idea resonates, a ⭐ helps a lot:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Repo: &lt;a href="https://github.com/alexar76/aicom" rel="noopener noreferrer"&gt;https://github.com/alexar76/aicom&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Live: &lt;a href="https://magic-ai-factory.com" rel="noopener noreferrer"&gt;https://magic-ai-factory.com&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;(No crypto in this post on purpose — the self-hosted/dev crowd bounces on it, and an earlier crypto-angled post of mine got exactly zero traction. The on-chain settlement story goes to Farcaster / the lottery post; here "get paid" stays a dev-tools hook.)&lt;/em&gt;&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>opensource</category>
      <category>ai</category>
      <category>llm</category>
    </item>
    <item>
      <title>We built a way to fine cheating AI agents. Then a swarm of AI reviewers found how to delete any competitor for $0.</title>
      <dc:creator>Alex</dc:creator>
      <pubDate>Sun, 13 Sep 2026 15:54:48 +0000</pubDate>
      <link>https://dev.to/alexar76/we-built-a-way-to-fine-cheating-ai-agents-then-a-swarm-of-ai-reviewers-found-how-to-delete-any-29mg</link>
      <guid>https://dev.to/alexar76/we-built-a-way-to-fine-cheating-ai-agents-then-a-swarm-of-ai-reviewers-found-how-to-delete-any-29mg</guid>
      <description>&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flxbtuceddj55kfa5072u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flxbtuceddj55kfa5072u.png" alt="We shipped a slashing rule for AI agents; an AI review swarm found a $0 attack" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We run an open marketplace where AI agents pay other AI agents to do work. Agent A needs a translation, calls Agent B, money moves, receipt signed. Standard stuff — until Agent B takes the money and returns garbage.&lt;/p&gt;

&lt;p&gt;So, like every payment network before us, we built &lt;strong&gt;slashing&lt;/strong&gt;: a provider posts a stake, and if they cheat, we burn part of it. A deterrent.&lt;/p&gt;

&lt;p&gt;Then we did the thing almost nobody does before shipping: we pointed an army of adversarial AI reviewers at our &lt;em&gt;own&lt;/em&gt; freshly-written code and told them to break it.&lt;/p&gt;

&lt;p&gt;They found a way to &lt;strong&gt;evict any competitor from the marketplace and burn their stake — for exactly $0.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We wrote that bug. This is the story of catching it, plus the four design ideas that made slashing usable in a multi-agent world in the first place.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why "just slash cheaters" falls apart
&lt;/h2&gt;

&lt;p&gt;A slash is a blunt instrument. In a single call it's fine. In a &lt;strong&gt;multi-agent pipeline&lt;/strong&gt; — A calls B calls C, a council votes, a chain of subcontractors — it breaks fast:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Slash &lt;em&gt;everyone&lt;/em&gt; in a failed pipeline and you punish honest hops for one bad neighbor.&lt;/li&gt;
&lt;li&gt;Slash hard and a new agent gets zeroed on its first bad day. No room to recover, no room to experiment.&lt;/li&gt;
&lt;li&gt;Make the trigger cheap and it becomes a weapon: grief a competitor into oblivion.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Our rule became: &lt;strong&gt;escrow protects the buyer on this call; slash only prices &lt;em&gt;serial&lt;/em&gt; fraud.&lt;/strong&gt; Everything below is in service of that line.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  1. Blame the hop, not the graph
&lt;/h3&gt;

&lt;p&gt;When a pipeline fails, the signed bill-of-materials now says &lt;em&gt;who&lt;/em&gt; failed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"blame"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"policy"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"hop-level"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"at_fault"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"b"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"product_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"p2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"status_code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"not_at_fault"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"a"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"not_executed"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"c"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fn86bs51mxurcqq94sq4z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fn86bs51mxurcqq94sq4z.png" alt="The signed bill-of-materials names the at-fault hop and clears the rest" width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hop &lt;code&gt;a&lt;/code&gt; already settled independently. Hop &lt;code&gt;c&lt;/code&gt; never ran. Only &lt;code&gt;b&lt;/code&gt; is on the hook — and because it's inside the signed receipt, that attribution is portable evidence a dispute can point at.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Calibrate: trust floor, not death penalty
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Below the failure threshold, you lose &lt;strong&gt;trust&lt;/strong&gt;, not stake.&lt;/li&gt;
&lt;li&gt;When a slash does fire: 5% of stake, capped at $5, one slash per cool-down window, plus a rolling &lt;strong&gt;24h cap&lt;/strong&gt; (default $10). One bad day can't zero a new agent.&lt;/li&gt;
&lt;li&gt;Failure streaks and slash events are &lt;strong&gt;persisted&lt;/strong&gt; — a hub restart no longer amnesties a streak or forgets the cap.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Federate with consensus, not vibes
&lt;/h3&gt;

&lt;p&gt;A cheater shouldn't just hop to another hub and reset. So slashes propagate across hubs as &lt;strong&gt;signed attestations&lt;/strong&gt; — in two tiers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Strong&lt;/strong&gt;: carries the original &lt;em&gt;consumer-signed&lt;/em&gt; proof-of-misbehavior. Unforgeable, so one hub is enough.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Weak&lt;/strong&gt;: an automated slash with no consumer signature. On its own it moves &lt;strong&gt;nothing&lt;/strong&gt;. It takes &lt;strong&gt;≥2 independent hubs&lt;/strong&gt; to agree, at half weight each.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# strong issuers count fully; weak issuers only as consensus
&lt;/span&gt;&lt;span class="n"&gt;effective&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;strong&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.5&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;weak&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;weak&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;penalty&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="n"&gt;effective&lt;/span&gt;   &lt;span class="c1"&gt;# 1→0.5, 2→0.75, 3→0.875 …
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhlhlu4w4qgyce6yqob1t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhlhlu4w4qgyce6yqob1t.png" alt="federated_penalty from the real code: one weak hub scores 0.0; agreement compounds" width="800" height="427"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One hub's mood is not evidence. Cross-hub agreement is.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Verify first, slash last
&lt;/h3&gt;

&lt;p&gt;Before any slash, quality gets checked. A verifier (our &lt;a href="https://github.com/alexar76/metis" rel="noopener noreferrer"&gt;Metis&lt;/a&gt; layer) audits the delivered result. A "failed" verdict &lt;strong&gt;refunds the buyer&lt;/strong&gt; from escrow and dings the provider's trust. Only &lt;em&gt;repeat&lt;/em&gt; verified failures escalate to stake — carrying the signed rejection receipt as evidence.&lt;/p&gt;

&lt;p&gt;Slash is the last resort, not the QA system.&lt;/p&gt;




&lt;h2&gt;
  
  
  Now the fun part: we attacked our own commit
&lt;/h2&gt;

&lt;p&gt;Tests were green. 400+ of them. In most shops that's "ship it."&lt;/p&gt;

&lt;p&gt;Instead we ran an &lt;strong&gt;adversarial review workflow&lt;/strong&gt;: a panel of reviewers, each taking a different angle (economic attacks, correctness, federation, concurrency, test coverage), and every finding then handed to three independent verifiers whose only job was to &lt;em&gt;refute&lt;/em&gt; it. Survive two of three and it's real.&lt;/p&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdhy2b3r0lwsnxe5jqpyd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdhy2b3r0lwsnxe5jqpyd.png" alt="We red-teamed our own commit: 32 candidate findings, each refuted by 3 skeptics, 12 survived, 1 critical" width="800" height="427"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Twelve findings survived. One was rated &lt;strong&gt;critical&lt;/strong&gt; — and it was in the verify-first ladder we'd just written.&lt;/p&gt;

&lt;h3&gt;
  
  
  The $0 eviction
&lt;/h3&gt;

&lt;p&gt;Here's the shape of the vulnerable code:&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;record_verified_failure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&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="n"&gt;publisher_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;product_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;capability_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rejection&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# a "failed" verdict → ding trust, and after N failures → slash stake
&lt;/span&gt;    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trust_add_edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_HUB_ANCHOR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;publisher_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;0.25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;verified_failure&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;supply_fault_log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;publisher_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;verified_failure&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;fails&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;policy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;verified_fail_threshold&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_slash_for_failure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;publisher_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...)&lt;/span&gt;   &lt;span class="c1"&gt;# burns stake
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Looks reasonable. Here's why it's a hole:&lt;/p&gt;

&lt;p&gt;The verifier judges the delivered result against the &lt;strong&gt;buyer's stated intent&lt;/strong&gt;. And that intent is a free-form string the &lt;em&gt;buyer&lt;/em&gt; supplies — completely decoupled from the actual request the provider answered.&lt;/p&gt;

&lt;p&gt;So as an attacker:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Call an honest provider with &lt;code&gt;input = "hi"&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;intent = "return a complete 500-page novel"&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The provider does its job correctly. The verifier compares the honest output to your impossible intent → &lt;strong&gt;verdict: failed.&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Do it three times. There was no check that the verification was &lt;em&gt;paid&lt;/em&gt; (advisory verdicts on a free/crypto-off hub reached the same code), no check that the failures came from &lt;em&gt;different&lt;/em&gt; buyers (one attacker supplied all three), and the trust hit was uncapped.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cost to the attacker: $0. No stake, no auth, no channel.&lt;/strong&gt; Result: a competitor's stake bleeds and their reputation craters until the hub refuses to route to them. A deterrent turned into a delete button.&lt;/p&gt;

&lt;h3&gt;
  
  
  The fix: make griefing expensive and plural
&lt;/h3&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyrkhlw130p6ht3u7m2qy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyrkhlw130p6ht3u7m2qy.png" alt="Before and after: record_verified_failure now gates on paid + ≥2 distinct buyers" width="800" height="474"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We rebuilt the ladder to mirror the same consensus principle the federation already used — &lt;em&gt;a lone actor moves nothing&lt;/em&gt;:&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;record_verified_failure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&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="n"&gt;publisher_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;consumer_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;paid&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&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;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;paid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;                     &lt;span class="c1"&gt;# advisory verdicts NEVER touch stake
&lt;/span&gt;    &lt;span class="n"&gt;consumer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;consumer_id&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;consumer:anonymous&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trust_add_edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;consumer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;publisher_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;0.25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;verified_failure&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# ← consumer, not hub anchor
&lt;/span&gt;    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;supply_fault_log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;publisher_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;verified_failure&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...,&lt;/span&gt; &lt;span class="n"&gt;consumer_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;consumer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;fails&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;supply_fault_count_recent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;publisher_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;verified_failure&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;distinct&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;supply_fault_distinct_consumers_recent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;publisher_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;verified_failure&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;fails&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;threshold&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;distinct&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;policy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;verified_fail_min_consumers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="c1"&gt;# default 2
&lt;/span&gt;        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_slash_for_failure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;publisher_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...,&lt;/span&gt; &lt;span class="n"&gt;evidence&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;rejection&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three changes, each closing part of the hole:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Paid-gate.&lt;/strong&gt; Only a real, escrow-backed transaction can feed the stake ladder. A free/advisory verdict can nudge reputation, never burn stake.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consumer attribution.&lt;/strong&gt; The trust hit hangs off the &lt;em&gt;consumer's&lt;/em&gt; node in the trust graph, not the hub anchor — so a low-rank/anonymous buyer's complaint carries little weight and can't be amplified.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Distinct-consumer consensus.&lt;/strong&gt; A slash needs the failure threshold &lt;strong&gt;and&lt;/strong&gt; ≥2 &lt;em&gt;different paying&lt;/em&gt; buyers. One buyer's repeated failures are one voice.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To grief now you need multiple funded channels each losing real fees — the economics flip from free to prohibitive.&lt;/p&gt;

&lt;h3&gt;
  
  
  What else the swarm caught
&lt;/h3&gt;

&lt;p&gt;The critical wasn't alone. The same pass found — in code &lt;em&gt;we&lt;/em&gt; wrote — a batch of real regressions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sybil re-opening (high).&lt;/strong&gt; Our shiny weak-tier federation accepted attestations from &lt;em&gt;untrusted, first-contact&lt;/em&gt; peers by default. Two throwaway hubs → consensus → competitor poisoned. Fixed: weak attestations count only from operator-trusted peers; unforgeable strong ones still flow from anyone.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-thread SQLite (high).&lt;/strong&gt; We'd handed the app's DB-backed registry to a background crawl worker, so a worker thread wrote the app's connection concurrently with request handlers. Gave the crawler its own connection; refresh the app view after.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Portability + durability + a double-count-on-crash race&lt;/strong&gt;, all found, all fixed and tested.&lt;/li&gt;
&lt;/ul&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fix4s15s7jdo6omt2t0sm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fix4s15s7jdo6omt2t0sm.png" alt="aimarket-hub test suite: 460 passed, 1 skipped" width="800" height="240"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Final tally: &lt;strong&gt;460 tests passing&lt;/strong&gt;, and — more importantly — a set of bugs that would have shipped silently behind a green checkmark.&lt;/p&gt;




&lt;h2&gt;
  
  
  The takeaways
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. "Tests pass" is not "safe" for economic code.&lt;/strong&gt; Our tests were green &lt;em&gt;and&lt;/em&gt; the code let anyone delete a competitor for free. Tests check the behaviors you thought of. An adversary attacks the ones you didn't.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Consensus beats authority, everywhere.&lt;/strong&gt; The same rule — &lt;em&gt;a lone actor moves nothing&lt;/em&gt; — fixed both the federation (≥2 hubs) and the griefing bug (≥2 buyers). When a single party can trigger a penalty, someone will automate it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Red-team your own diff, out loud.&lt;/strong&gt; The highest-leverage move wasn't a clever algorithm; it was pointing skeptics at fresh code with the explicit goal of breaking it, and demanding a concrete exploit — inputs → wrong outcome — before believing any finding.&lt;/p&gt;

&lt;p&gt;There's a pleasing symmetry here: we used a &lt;strong&gt;multi-agent workflow&lt;/strong&gt; to harden a &lt;strong&gt;multi-agent marketplace&lt;/strong&gt;. Agents reviewing the rules that will one day slash agents.&lt;/p&gt;

&lt;p&gt;It's all open source. If you're building anything where software can lose money on someone's behalf — an agent marketplace, a staking system, an automated escrow — go find your own $0 attack before someone else does.&lt;/p&gt;

&lt;p&gt;→ &lt;strong&gt;Code:&lt;/strong&gt; &lt;a href="https://github.com/alexar76/aicom" rel="noopener noreferrer"&gt;github.com/alexar76/aicom&lt;/a&gt;&lt;br&gt;
→ &lt;strong&gt;Verifier layer (Metis):&lt;/strong&gt; &lt;a href="https://github.com/alexar76/metis" rel="noopener noreferrer"&gt;github.com/alexar76/metis&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Got a collab pattern you think would break this — a council vote, a long subcontract chain? Drop it in the comments; I'll walk through how a slash gets attributed.&lt;/em&gt;&lt;/p&gt;

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