<?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: Matt Hamilton</title>
    <description>The latest articles on DEV Community by Matt Hamilton (@hammertoe).</description>
    <link>https://dev.to/hammertoe</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%2F386069%2F587bae2a-4c3f-465c-a2ea-19447bc679d7.jpg</url>
      <title>DEV Community: Matt Hamilton</title>
      <link>https://dev.to/hammertoe</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/hammertoe"/>
    <language>en</language>
    <item>
      <title>From a half-finished training run to a reproducible eval</title>
      <dc:creator>Matt Hamilton</dc:creator>
      <pubDate>Wed, 12 Aug 2026 16:17:11 +0000</pubDate>
      <link>https://dev.to/hammertoe/from-a-half-finished-training-run-to-a-reproducible-eval-1k78</link>
      <guid>https://dev.to/hammertoe/from-a-half-finished-training-run-to-a-reproducible-eval-1k78</guid>
      <description>&lt;p&gt;So our last training pass on &lt;code&gt;Qwen3-Omni-30B-A3B-Instruct&lt;/code&gt; — fine-tuning it on Barbados newspapers — ran out of time halfway through. Twelve hours of GPU budget, planned for 1624 training steps, finished at step 1000. Loss was still falling. The full checkpoint, optimiser state, scheduler — everything you need to keep going — was sitting safely in a private cloud bucket. So we restarted it. Then the interesting bit happened.&lt;/p&gt;

&lt;p&gt;The headline finding is the +5 percentage points on the 60-probe text knowledge eval (reproducible to 0pp on the same stack). The bigger finding is the radio audio number, which roughly doubled on completion. Both point to the same conclusion: completing the training schedule to step 1624 mattered.&lt;/p&gt;

&lt;h2&gt;
  
  
  Context: Future Caribbean and Pulse
&lt;/h2&gt;

&lt;p&gt;This work is part of &lt;a href="https://futurecaribbean.com" rel="noopener noreferrer"&gt;Future Caribbean&lt;/a&gt;, a regional initiative that runs a global agentic AI buildathon over a 21-day sprint each summer. The framing is "build deployable AI systems that strengthen how economies coordinate" — ten tracks, $70K+ in prizes, and a final showcase at the NYSE. We're one of the selected teams.&lt;/p&gt;

&lt;p&gt;The programme advertised NVIDIA H200-class compute for selected teams, and we planned this training work on that basis. In practice, compute was not made available to our team during the build window. Rather than drop the model work, I rented the H200 capacity personally through Hugging Face Jobs. That is a decision worth flagging: access to compute materially shapes what small teams can attempt in a three-week buildathon, and going it alone means we could only train the model once, on the budget I could afford.&lt;/p&gt;

&lt;p&gt;Our build is &lt;strong&gt;Pulse&lt;/strong&gt; — a live public-signal intelligence system for Barbados that continuously ingests fragmented social, broadcast, and news signals, resolves them into a trusted graph of sources, places, events, people, and communities, and exposes that intelligence through agentic workflows. The Barbados LoRA is one of the domain-knowledge components feeding into Pulse's natural language layer.&lt;/p&gt;

&lt;p&gt;The model itself isn't Pulse-specific. It's a standard text-only LoRA on a standard base model, trained on a Barbados newspaper archive. The source corpus is private, but the adapter is public. Anyone working on Caribbean-domain text — search, summarisation, knowledge probes, a personal project on Bajan history — can download and use the V4 artefacts directly. You don't need to be running Pulse to benefit from the training, and Pulse isn't the only reason the model exists.&lt;/p&gt;

&lt;h2&gt;
  
  
  The setup, briefly
&lt;/h2&gt;

&lt;p&gt;Domain-adaptive pretraining (DAPT) is the simplest "teach a model something new" technique you can run: take a model that's already been trained on the open web, and continue its next-token prediction on a corpus from your target domain. No labels, no chat format, no reward model. Just keep showing it text and let the loss fall. Gururangan and colleagues at ACL 2020 called this &lt;a href="https://aclanthology.org/2020.acl-main.740/" rel="noopener noreferrer"&gt;Don't Stop Pretraining&lt;/a&gt; — the follow-up paper that established the technique.&lt;/p&gt;

&lt;p&gt;In our case the corpus is the cleaned Barbados newspaper archive, the base model is a 30-billion-parameter multimodal MoE, and the fine-tune is a small low-rank adapter (LoRA) on the text-only "thinker" half of the model. Training runs on a rented H200 GPU inside a Hugging Face Job. This post is about what happened when we tried to finish the schedule and what re-scoring the older artefacts taught us.&lt;/p&gt;

&lt;h2&gt;
  
  
  The mistake that shaped the recipe
&lt;/h2&gt;

&lt;p&gt;The first real training run only touched the Thinker's attention projections — the &lt;code&gt;q&lt;/code&gt;, &lt;code&gt;k&lt;/code&gt;, &lt;code&gt;v&lt;/code&gt;, and &lt;code&gt;o&lt;/code&gt; projection layers around each attention head. That made 53.5 million parameters trainable: 0.17% of the 31.8-billion-parameter base model. The reasoning at the time was that attention is where the model decides which knowledge to retrieve, and retargeting that was the cheapest plausible intervention. We called it V2.&lt;/p&gt;

&lt;p&gt;The mistake was thinking that was enough. On the GPU paired path (LoRA loaded at runtime into a bf16 base), V2 helped. On the 4-bit fused path that Pulse actually runs — the LoRA merged into the weights, then quantised — V2 &lt;em&gt;regressed&lt;/em&gt;. 55% overall, against 61.7% for the unfine-tuned 4-bit base. Fusing an attention-only LoRA into a 4-bit snapshot loses more fidelity than the same adapter applied at runtime. The base model still knew things the fused V2 didn't.&lt;/p&gt;

&lt;p&gt;Imagine the model as a library. Attention is the librarian deciding which shelves and passages matter for the question. The MLP/MoE pathway is more like the subject specialists who read that material, transform it, and connect it to other facts. Retraining the librarian — V2 — changed where the model looked. It did not change the specialists' working knowledge. On a paired eval the librarian can be enough: the specialists still know what they knew. Fused into 4-bit weights, the librarian's retraining doesn't survive the round-trip cleanly, and the specialists never moved at all.&lt;/p&gt;

&lt;p&gt;The later recipe kept the attention targets and added LoRA parameters to the Thinker's MLP/MoE pathway (&lt;code&gt;gate_up_proj&lt;/code&gt; and &lt;code&gt;down_proj&lt;/code&gt;). That expanded the trainable surface to about 2.59 billion parameters, or 7.54% of the base model. In library terms, we could now retrain both the librarian and the subject specialists. V3 stopped partway through that broader schedule. V4 is the completed version. The +15pp jump from V2 (55%) to V3 (70%) is the recipe change doing real work — not the schedule completing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Picking up where we left off
&lt;/h2&gt;

&lt;p&gt;Resuming a Hugging Face Job is conceptually simple: launch a new job that points at the same run identifier. The bucket-and-sidecar architecture (the worker continuously uploads checkpoint snapshots to a private bucket as it trains) handles the bookkeeping — when a fresh training job starts, it asks the bucket "what's the latest complete snapshot for this run?" and picks up from there.&lt;/p&gt;

&lt;p&gt;In practice there were two things to be careful about. First, the resume check enforces recipe identity strictly — it compares a hash of the training config (base model, dataset, LoRA shape, library versions, the &lt;em&gt;image digest of the container&lt;/em&gt;) against the snapshot it's about to restore. So we couldn't use the rebuilt container image that fixes an upload bug elsewhere in the pipeline; the manifest wouldn't match, the resume would silently skip the bucket, and we'd start a brand new run instead. We used the original container and dealt with the upload bug the same way we did for V3: don't trust the in-process adapter upload, publish the final adapter in a separate recovery job.&lt;/p&gt;

&lt;p&gt;Second, that recovery job hardcoded the destination repository name in the supervisor code, pointing at V3. There was no flag to override it. Three-line code change to fix, but the cleanest workaround without rebuilding the container was an inline Python script that calls the same upload primitives with a different target — published &lt;code&gt;…-LoRA-v4&lt;/code&gt; in 61 seconds. Then a single &lt;code&gt;finalise&lt;/code&gt; job produced the fused bf16 and the 4-bit MLX snapshots (the latter is what you actually run on a Mac). Both published, both verified — the provenance file correctly lists &lt;code&gt;adapter: …-LoRA-v4&lt;/code&gt; rather than the V3 adapter a publishing bug had caught in an earlier round.&lt;/p&gt;

&lt;p&gt;The full resume, including one sidecar-marker hiccup that took a two-minute manual fix, is recorded in &lt;code&gt;docs/19&lt;/code&gt; §10.2.&lt;/p&gt;

&lt;h2&gt;
  
  
  The result
&lt;/h2&gt;

&lt;p&gt;Three runs on the same 60-probe Barbados knowledge set — twenty well-known local facts (parliament year, Crop Over revival, parish count), twenty niche ones (Barrow constituency, Leadpipe Glitch, Grantley Adams Secondary), and twenty general-knowledge controls (longest European river, deepest trench, Marie Curie). The model picks one of four candidate completions for each probe by ranking them on mean log-probability over the completion tokens. Right or wrong.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Run&lt;/th&gt;
&lt;th&gt;Recipe&lt;/th&gt;
&lt;th&gt;Schedule&lt;/th&gt;
&lt;th&gt;Overall&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;V2&lt;/td&gt;
&lt;td&gt;attention only (&lt;code&gt;q/k/v/o_proj&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;500 / 801 steps · 53.5M params&lt;/td&gt;
&lt;td&gt;55.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;V3&lt;/td&gt;
&lt;td&gt;attention + MLP/MoE&lt;/td&gt;
&lt;td&gt;1000 / 1624 steps · 2.59B params&lt;/td&gt;
&lt;td&gt;70.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;V4&lt;/td&gt;
&lt;td&gt;attention + MLP/MoE (completed)&lt;/td&gt;
&lt;td&gt;1624 / 1624 steps · 2.59B params&lt;/td&gt;
&lt;td&gt;75.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;base&lt;/td&gt;
&lt;td&gt;unfine-tuned 4-bit&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;61.7%&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%2Fao098txphzawm9j78hre.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%2Fao098txphzawm9j78hre.png" alt="Overall accuracy on the 60-probe Barbados text knowledge eval — base 4-bit, then V2, V3, V4 fused 4-bit" width="800" height="512"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The V2 number is the most important one in the table. The attention-only recipe &lt;em&gt;helped&lt;/em&gt; on a GPU paired eval (LoRA loaded at runtime into a bf16 base) — a result from earlier in the project that I wrote up at the time. But on the 4-bit fused path that Pulse actually runs, V2 scored worse than base: 55% against 61.7%. Fusing an attention-only LoRA into a 4-bit snapshot loses more fidelity than fusing one that also has MLP/MoE parameters. V3's recipe change — adding LoRA to &lt;code&gt;gate_up_proj&lt;/code&gt; and &lt;code&gt;down_proj&lt;/code&gt; — is what brought the fused 4-bit path back to parity. The +15pp jump from V2 (55%) to V3 (70%) is the recipe change doing real work, not the schedule completing.&lt;/p&gt;

&lt;p&gt;V4 then completes the schedule V3 started, lifting another 5pp on top.&lt;/p&gt;

&lt;p&gt;The reproducibility question was whether +5pp on the V3 → V4 step was real or evaluator drift. The eval script's hardcoded model-repo field pointed at V3, the MLX backend is sensitive to small numerical changes between versions, and 5pp on 60 probes is roughly three probes — within sample noise. The honest test was to re-score the earlier artefacts on the same stack — V3's fused 4-bit snapshot and the unfine-tuned base, both downloaded from the Hub.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Track&lt;/th&gt;
&lt;th&gt;base&lt;/th&gt;
&lt;th&gt;V3&lt;/th&gt;
&lt;th&gt;V4&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;local&lt;/td&gt;
&lt;td&gt;55.0%&lt;/td&gt;
&lt;td&gt;65.0%&lt;/td&gt;
&lt;td&gt;70.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;rare_local&lt;/td&gt;
&lt;td&gt;40.0%&lt;/td&gt;
&lt;td&gt;55.0%&lt;/td&gt;
&lt;td&gt;60.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;control&lt;/td&gt;
&lt;td&gt;90.0%&lt;/td&gt;
&lt;td&gt;90.0%&lt;/td&gt;
&lt;td&gt;95.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;overall&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;61.7%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;70.0%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;75.0%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;All three reproduce to &lt;strong&gt;0pp&lt;/strong&gt; of their originally-recorded numbers. The eval path is stable. The +5pp V3 → V4 is real weight movement. The cumulative DAPT contribution (base → V4) is &lt;strong&gt;+13.3pp overall&lt;/strong&gt;: +3 local, +4 rare_local, +1 control.&lt;/p&gt;

&lt;h2&gt;
  
  
  The interesting bit
&lt;/h2&gt;

&lt;p&gt;So the +5pp is real, but the mechanism is interesting. On the 34 probes that both the base model and V4 got right, V4's mean margin (the gap between the top-ranked correct completion and the runner-up) is &lt;strong&gt;0.56 log-prob *smaller&lt;/strong&gt;* than the base model's. V4 is &lt;em&gt;less&lt;/em&gt; confident on the easy probes it shares with the base model, yet wins more probes overall.&lt;/p&gt;

&lt;p&gt;This is the signature of a model that's been retargeted toward a domain. The output layer has shifted to put more weight on Barbados-relevant tokens, which compresses the log-probability gap on general-completion probes where those tokens weren't relevant, while flipping close calls on the domain probes where they are. Same total budget, redistributed. The accuracy gain comes from breaking ties on the borderline probes, not from being more confident on what's already easy.&lt;/p&gt;

&lt;p&gt;The +1 control-probe gain (a paraphrasing probe the base and V3 both missed) is also real and slightly unexpected. V4 picks up some paraphrasing robustness from incidental general prose in the corpus (sports, world news, op-eds). One probe on N=20 is suggestive rather than load-bearing, but it does mean V4 is genuinely a better model, not just a better Barbados model.&lt;/p&gt;

&lt;h2&gt;
  
  
  Does it survive contact with actual audio?
&lt;/h2&gt;

&lt;p&gt;The 60-probe eval is text-only — it asks whether the model knows facts about Barbados. Pulse's actual workload is audio: five-minute FM radio windows and short-form TikToks that need transcription and structured extraction (events, venues, prices, promotions). Two more evals cover that path.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Radio — 17 five-minute windows&lt;/strong&gt; from real Barbados FM (HOTT 95.3, VOB 92.9, CBC 94.7, Life 97.5, Q 100.7, The Beat 104.1, The One 98.1, Y 103.3, Radio Bimshire 106.1, SLAM 101.1). Scored on quality, hallucination rate, proper-noun precision/recall, event false-positive and false-negative rates, and whether evidence quotes survive.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Windows&lt;/th&gt;
&lt;th&gt;Avg quality&lt;/th&gt;
&lt;th&gt;Avg latency&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;base&lt;/td&gt;
&lt;td&gt;17&lt;/td&gt;
&lt;td&gt;0.135&lt;/td&gt;
&lt;td&gt;9.2s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;V3&lt;/td&gt;
&lt;td&gt;17&lt;/td&gt;
&lt;td&gt;0.140&lt;/td&gt;
&lt;td&gt;15.5s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;V4&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;17&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.230&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;17.8s&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%2Fkhbvfsxjuhiixbu9wwlq.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%2Fkhbvfsxjuhiixbu9wwlq.png" alt="Radio audio extraction — V4 nearly doubles V3's quality score" width="800" height="514"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;V3 was essentially flat against base on radio. Completing the LR schedule to step 1624 nearly doubled the audio extraction quality (0.140 → 0.230). The place where DAPT shows up most clearly is the proper-noun layer: "Rise Together" instead of "Rice Together", "Leadpipe and Sadis" instead of plumbing+typo. These errors are unrecoverable once cheap Whisper has destroyed them, so the audio-tower-bearing model is the only place to fix them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TikTok — 10 Barbados TikToks&lt;/strong&gt; (golf promotions, catamaran cruises, cave tours, farmers' markets, flower forests, rug-making workshops). Each fixture has hand-written ground truth for the observations the pipeline should extract.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Precision&lt;/th&gt;
&lt;th&gt;Recall&lt;/th&gt;
&lt;th&gt;F1&lt;/th&gt;
&lt;th&gt;Field recall&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;base&lt;/td&gt;
&lt;td&gt;0.26&lt;/td&gt;
&lt;td&gt;0.36&lt;/td&gt;
&lt;td&gt;0.30&lt;/td&gt;
&lt;td&gt;0.42&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;V3&lt;/td&gt;
&lt;td&gt;0.60&lt;/td&gt;
&lt;td&gt;0.55&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.57&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0.38&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;V4&lt;/td&gt;
&lt;td&gt;0.34&lt;/td&gt;
&lt;td&gt;0.55&lt;/td&gt;
&lt;td&gt;0.42&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.52&lt;/strong&gt;&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%2Fctircfzb0gzz0s6xxdif.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%2Fctircfzb0gzz0s6xxdif.png" alt="TikTok extraction — V3 wins on precision, V4 wins on field recall" width="800" height="424"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;V4 and V3 are tied on recall (0.55) — both find the right observations. They diverge on what they do around the edges. V3 is more conservative: higher precision (fewer false positives), lower field recall (less detail per observation). V4 emits more candidate entities per fixture (35 vs V3's 20 across all 10) and fills more fields correctly per observation, but at the cost of more false positives. That's the same calibration shift showing up in a different modality: V4's unembedding has broadened its candidate distribution, which helps coverage and hurts precision.&lt;/p&gt;

&lt;p&gt;There is a fair question about whether V4's precision drop is a real regression or an artefact of the benchmark itself. The ground truth for each fixture is hand-written — one to six expected observations per video. When V4 emits a correct observation that isn't in that small gold set, the scorer counts it as a false positive. The model isn't wrong; the ground truth is incomplete. This is a known problem in information-extraction evaluation, and we're working on better benchmarks that separate raw transcription accuracy from knowledge extraction quality, and that don't punish a model for finding more than the annotator thought to write down.&lt;/p&gt;

&lt;p&gt;If that benchmark design question is more interesting to you than the model, I wrote a whole separate post on it: &lt;a href="https://dev.to/hammertoe/when-your-benchmark-is-wrong-and-your-model-is-right-p74"&gt;When your benchmark is wrong and your model is right&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The V4 artefacts are on Huggingface at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;hammertoe/Qwen3-Omni-30B-A3B-Barbados-LoRA-v4&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;hammertoe/Qwen3-Omni-30B-A3B-Barbados-fused-bf16-v4&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;hammertoe/Qwen3-Omni-30B-A3B-Barbados-4bit-v4&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want to take V4 for a spin, the model card on each Hub repo walks through download, the supported prompt format, and the activation-check probe that proves the adapter is wired up. &lt;/p&gt;

&lt;p&gt;Stay tuned for the next iteration. I want to try a longer schedule to see if +13.3pp is in fact a ceiling for this recipe, or whether the calibration shift keeps compounding as the model spends more time in the corpus.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>When your benchmark is wrong and your model is right</title>
      <dc:creator>Matt Hamilton</dc:creator>
      <pubDate>Wed, 12 Aug 2026 15:39:03 +0000</pubDate>
      <link>https://dev.to/hammertoe/when-your-benchmark-is-wrong-and-your-model-is-right-p74</link>
      <guid>https://dev.to/hammertoe/when-your-benchmark-is-wrong-and-your-model-is-right-p74</guid>
      <description>&lt;p&gt;When your benchmark is wrong and your model is right&lt;/p&gt;

&lt;p&gt;We fine-tuned a 30-billion-parameter model on Barbados newspapers. Then we had to write three different benchmarks to figure out whether it actually got better. It did — but not in the way any single benchmark could show on its own, and one of them made it look worse before it looked better.&lt;/p&gt;

&lt;p&gt;This is about the benchmarks, not the model. The model is &lt;a href="https://huggingface.co/Qwen/Qwen3-Omni-30B-A3B-Instruct" rel="noopener noreferrer"&gt;Qwen3-Omni-30B-A3B-Instruct&lt;/a&gt; with a LoRA adapter trained on a cleaned Barbados newspaper archive. We're building Pulse, a live public-signal intelligence system for Barbados — radio, newspapers, TikTok, and government feeds turned into a queryable knowledge graph — as part of &lt;a href="https://futurecaribbean.com" rel="noopener noreferrer"&gt;Future Caribbean&lt;/a&gt;, a 21-day agentic AI buildathon. Pulse is still in active development. The fine-tuned model is one of its domain-knowledge components, and it's also published openly for anyone working on Caribbean-domain text.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three benchmarks, three answers
&lt;/h2&gt;

&lt;p&gt;The model went through two versions. V3 stopped halfway through its training schedule (step 1000 of 1624, when the 12-hour GPU budget ran out). V4 resumed and completed the full schedule to step 1624. We scored both against the unmodified base model on three different eval tracks.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Text knowledge probe — 60 multiple-choice questions
&lt;/h3&gt;

&lt;p&gt;Twenty well-known Barbados facts, twenty niche ones, and twenty general-knowledge controls. Scored by mean token log-probability over four candidate completions. Clean, reproducible, deterministic.&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%2Fikkzf3krazqfxvwsnplb.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%2Fikkzf3krazqfxvwsnplb.png" alt="Text knowledge probe — three models across four tracks" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;V4 wins across the board. The DAPT contribution is real (+13.3pp overall vs base). This benchmark is the one I'd cite if someone asked "did the fine-tuning work?".&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Radio audio extraction — 17 five-minute FM windows
&lt;/h3&gt;

&lt;p&gt;Real Barbados radio captures (HOTT 95.3, VOB 92.9, CBC 94.7, and seven others). The model hears the audio and emits structured JSON: corrected transcript, events, entities, facts. Scored on quality, hallucination rate, proper-noun precision/recall, and evidence-quote presence.&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%2Fjjkwq420zdyo524vkkiy.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%2Fjjkwq420zdyo524vkkiy.png" alt="Radio audio extraction — average quality score per model" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;V3 was essentially flat against base on this benchmark. V4 nearly doubled the quality score. The difference is proper nouns: the model that has read a thousand editions of the &lt;em&gt;Barbados Advocate&lt;/em&gt; hears "Rise Together" (a Crop Over event) instead of "Rice Together". That is the entire reason we fine-tuned.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. TikTok extraction — 10 short videos
&lt;/h3&gt;

&lt;p&gt;Barbados TikToks: golf promotions, catamaran cruises, cave tours, farmers' markets. Each has hand-written ground truth for the structured observations the pipeline should extract. Scored on field-level precision, recall, and F1.&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%2F2mvfn0xw4v2t4llbust0.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%2F2mvfn0xw4v2t4llbust0.png" alt="TikTok extraction — precision, recall, and F1 per model" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;V4 is worse than V3 here. That is the interesting bit.&lt;/p&gt;

&lt;h2&gt;
  
  
  What "worse" means
&lt;/h2&gt;

&lt;p&gt;V4 and V3 find the same number of correct observations (12 true positives each). V4 emits 23 false positives; V3 emits 8. The difference is 15 extra observations that don't match anything in the ground truth.&lt;/p&gt;

&lt;p&gt;I dug into where those 15 extras come from. Two patterns.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Over-emission.&lt;/strong&gt; On a 65-second catamaran cruise video, V3 emitted 1 observation. V4 emitted 9 — the same catamaran cruise, three times (as duplicates), plus separate "promotion" objects for "drinks were already flowing", "so many options and variety", and "staff were super friendly". Every positive sentence in the review got its own JSON object. V4 found both expected observations (V3 found neither), but buried them in noise.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Type confusion.&lt;/strong&gt; On an itinerary TikTok listing eight things to do, V3 emitted five &lt;code&gt;event_occurrence&lt;/code&gt; objects: racehorses at Pebble Beach, sunrise on the east side, yacht charter, St Nicholas Abbey, Hammers Market. V4 saw the same content but emitted three of them as &lt;code&gt;entity_mention&lt;/code&gt; instead — just the place name, without the activity context. The scorer matches on observation type first, so those became false positives (wrong type) while the expected events became false negatives (unmatched).&lt;/p&gt;

&lt;p&gt;Both patterns share a root cause. Completing the training schedule broadened the model's sensitivity to Barbados content. Its output layer now fires more readily on domain tokens — place names, venue names, activity descriptions. In the text probe this shows up as higher accuracy. In audio extraction it shows up as better proper-noun transcription. In structured extraction it shows up as over-triggering: the model sees Barbados signal everywhere because it has been trained to.&lt;/p&gt;

&lt;h2&gt;
  
  
  The benchmark is the bottleneck
&lt;/h2&gt;

&lt;p&gt;The TikTok eval has a scoring problem, and it took V4 to expose it.&lt;/p&gt;

&lt;p&gt;The ground truth for each fixture is hand-written: one to six expected observations per video, each with specific fields (name, location, category, price). It is a small, fixed target. When V4 emits a correct observation that isn't in the ground truth — say, "snorkelling at the first stop" on the catamaran video — the scorer counts it as a false positive. The model isn't wrong; the ground truth is incomplete.&lt;/p&gt;

&lt;p&gt;This is a known problem in information-extraction evaluation. Strict precision against a small gold set punishes models that extract more than the annotator thought to write down. The right fix is either a larger gold set, a human-in-the-loop review of every "false positive" to separate real hallucinations from under-annotated ground truth, or a softer scoring rubric that rewards partially-correct observations instead of treating them as binary hits or misses.&lt;/p&gt;

&lt;p&gt;We're now moving toward the second option: a review pass over every V4 "false positive" to classify it as a real hallucination (the model invented something that isn't in the audio) or an annotation gap (the model found something correct that the ground truth missed). That will give us a corrected precision number that reflects the model's actual quality, not the ground truth's coverage.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benchmarks evolve with the model
&lt;/h2&gt;

&lt;p&gt;When we started, the 60-probe text eval was the only benchmark. It was designed to answer a simple question: does the adapter know more about Barbados than the base model? It does, reproducibly, and that question is answered.&lt;/p&gt;

&lt;p&gt;But the text probe doesn't test what Pulse actually does. Pulse ingests audio — radio and TikTok — and extracts structured events from it. The radio eval was built next, and it revealed that V3 (the half-finished model) was barely better than base on audio extraction despite scoring +8pp on the text probe. That finding motivated resuming the training to produce V4, which is where the audio quality jumped.&lt;/p&gt;

&lt;p&gt;Then the TikTok eval revealed that V4, the better model by every other measure, over-triggers on structured extraction. That finding is now driving the ground-truth review, which will in turn produce a better benchmark for the next model version.&lt;/p&gt;

&lt;p&gt;Each benchmark answered one question and exposed the next one. The text probe asked "does it know more?". The radio eval asked "can it hear better?". The TikTok eval asked "can it extract cleanly?". The answers are yes, yes, and "it depends on how you score it".&lt;/p&gt;

&lt;p&gt;That is not a failure of evaluation. It is what evaluation looks like when you are building something new. You write the benchmark you can write. You run it. It tells you something true but incomplete. The incompleteness becomes visible only when the model outgrows the benchmark's assumptions. Then you write the next one.&lt;/p&gt;

&lt;p&gt;The alternative — waiting until you have a perfect benchmark before training — is a good way to never train at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where we are now
&lt;/h2&gt;

&lt;p&gt;We're still in development, not production. The V4 numbers are encouraging — its audio extraction quality (0.230 vs base's 0.135) is the difference between a pipeline that transcribes "Rice Together" and one that transcribes "Rise Together". For a system whose job is to tell you what's happening in Barbados tonight, that is the whole game. But encouraging numbers on a small eval set are not the same as a model ready to ship.&lt;/p&gt;

&lt;p&gt;What we're doing now is refining the benchmarks themselves. The TikTok precision regression made it clear that our extraction eval was scoring the wrong thing — punishing correct observations that the ground truth didn't anticipate. So we're splitting the evals along the lines of what actually matters to Pulse's use cases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Raw transcription accuracy&lt;/strong&gt; — does the model hear the right words?
This is the proper-noun problem: "Rise Together" vs "Rice Together", "Leadpipe and Sadis" vs plumbing and a typo. It's a clean, scoreable metric that directly reflects whether the DAPT investment paid off.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Knowledge extraction quality&lt;/strong&gt; — given the right words, does the
model produce the right structured output? This is where the over-emission and type confusion show up, and where the scoring rubric needs to evolve beyond binary hit/miss against a small gold set.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are different skills and they need different benchmarks. The current eval conflates them — a model can transcribe perfectly but still score zero on extraction because it emitted the wrong observation type, or because the ground truth didn't list the entity it found. Splitting them apart will tell us whether V4's regression is a hearing problem (it isn't — transcription is better than ever) or a formatting problem (it is — the model over-triggers on domain content).&lt;/p&gt;

&lt;p&gt;The model artefacts are published openly at &lt;a href="https://huggingface.co/hammertoe/Qwen3-Omni-30B-A3B-Barbados-LoRA-v4" rel="noopener noreferrer"&gt;hammertoe/Qwen3-Omni-30B-A3B-Barbados-LoRA-v4&lt;/a&gt; (adapter), &lt;a href="https://huggingface.co/hammertoe/Qwen3-Omni-30B-A3B-Barbados-fused-bf16-v4" rel="noopener noreferrer"&gt;…-fused-bf16-v4&lt;/a&gt; (fused weights), and &lt;a href="https://huggingface.co/hammertoe/Qwen3-Omni-30B-A3B-Barbados-4bit-v4" rel="noopener noreferrer"&gt;…-4bit-v4&lt;/a&gt; (4-bit MLX for Apple Silicon). You don't need to be running Pulse to use them — any Caribbean-domain NLP task can benefit.&lt;/p&gt;

&lt;p&gt;If you have ideas for better extraction scoring against under-annotated ground truth, I'd love to hear them.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>Teaching an Audio Model More About Barbados</title>
      <dc:creator>Matt Hamilton</dc:creator>
      <pubDate>Fri, 07 Aug 2026 00:30:31 +0000</pubDate>
      <link>https://dev.to/hammertoe/teaching-an-audio-model-more-about-barbados-32o2</link>
      <guid>https://dev.to/hammertoe/teaching-an-audio-model-more-about-barbados-32o2</guid>
      <description>&lt;p&gt;Automatic speech recognition is very good until somebody mentions the name of a local school, a village, a politician, a festival, or a cricket ground.&lt;/p&gt;

&lt;p&gt;Then things get strange.&lt;/p&gt;

&lt;p&gt;In an earlier test with audio from Barbados, GPT Transcribe and GPT Audio 1.5 heard the event name “Rise Together” as “Rice Together”, while Qwen3.5-Omni Plus and Flash got it right. Those are different models from the Qwen3-Omni checkpoint used here, but the result motivated this experiment. Acoustically, the mistake is understandable. Culturally, it is wrong. A person who knows the local context has another signal available: they know that &lt;em&gt;Rise Together&lt;/em&gt; is the plausible name.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;That led me to a question: can we give an audio-native model a stronger model of Barbados, using text that already contains the names, institutions, places, events and relationships it is likely to hear?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So I took an archive of Barbados newspapers, turned it into 51.6 million tokens, and used it for domain-adaptive pretraining of the Thinker inside Qwen3-Omni.&lt;/p&gt;

&lt;p&gt;The result is promising, but not conclusive. The adapted model produced higher scores on our preliminary Barbados knowledge probe, particularly on people and institutions. It also got slightly worse on a small set of general-knowledge controls. And, most importantly, we have not yet shown that it transcribes audio more accurately.&lt;/p&gt;

&lt;p&gt;This is a very preliminary result. It came from our first training run, which we stopped at step 500 of a planned 801 steps. We were also still extracting the newspaper archive, so the 51.6 million training tokens represent the material available for that run rather than the full corpus we ultimately intend to use.&lt;/p&gt;

&lt;p&gt;This post is about what we have actually demonstrated, what broke along the way, and why I think the experiment is still worth pursuing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem Is Not Just Acoustic
&lt;/h2&gt;

&lt;p&gt;A transcription model is doing more than converting sound into letters.&lt;/p&gt;

&lt;p&gt;When audio is clean and a word is common, the acoustic evidence can be enough. But real radio is compressed. Music leaks into speech. Presenters talk quickly. Phone-in guests have different microphones and accents. Proper nouns may be rare or absent from a model's original training data.&lt;/p&gt;

&lt;p&gt;At that point, transcription becomes a contest between plausible sequences:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;weak acoustic evidence + language context -&amp;gt; selected transcript
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For Barbados, the useful context includes things such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Kensington Oval&lt;/li&gt;
&lt;li&gt;Cave Hill&lt;/li&gt;
&lt;li&gt;Samuel Jackman Prescod Polytechnic&lt;/li&gt;
&lt;li&gt;Crop Over&lt;/li&gt;
&lt;li&gt;constituency and parish names&lt;/li&gt;
&lt;li&gt;local politicians, athletes, performers and organisations&lt;/li&gt;
&lt;li&gt;the ordinary relationships between all of those things&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is related to contextual biasing in automatic speech recognition. In &lt;a href="https://arxiv.org/abs/1808.02480" rel="noopener noreferrer"&gt;Deep Context&lt;/a&gt;, Pundak and colleagues showed that an end-to-end recogniser could use supplied contextual phrases, including out-of-vocabulary terms, and reported relative word-error-rate improvements of up to 68% on their tasks. Later work on &lt;a href="https://arxiv.org/abs/2104.02194" rel="noopener noreferrer"&gt;trie-based deep biasing and shallow fusion&lt;/a&gt; reported a 19.5% relative improvement over existing contextual-biasing methods, with particular attention to rare long-tail words.&lt;/p&gt;

&lt;p&gt;Those systems explicitly supply a biasing list at inference time. Our approach is different: we are trying to make local context part of the model's learned language prior. The papers do not validate our method directly, but they do support the underlying idea that context can help a recogniser resolve rare and ambiguous language.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Qwen3-Omni?
&lt;/h2&gt;

&lt;p&gt;I selected &lt;a href="https://huggingface.co/Qwen/Qwen3-Omni-30B-A3B-Instruct" rel="noopener noreferrer"&gt;Qwen3-Omni-30B-A3B-Instruct&lt;/a&gt; because it is natively multimodal. It accepts text, audio, images and video, and it can produce text or speech. More importantly for this experiment, its audio understanding and text generation are parts of one end-to-end architecture.&lt;/p&gt;

&lt;p&gt;According to the &lt;a href="https://arxiv.org/abs/2509.17765" rel="noopener noreferrer"&gt;Qwen3-Omni technical report&lt;/a&gt;, the model uses a Mixture-of-Experts Thinker-Talker design:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;Thinker&lt;/strong&gt; consumes multimodal representations and generates text.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;Talker&lt;/strong&gt; is responsible for generating streaming speech tokens.&lt;/li&gt;
&lt;li&gt;An Audio Transformer, or &lt;strong&gt;AuT&lt;/strong&gt;, turns audio into representations consumed by the Thinker.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Thinker has roughly 30 billion total parameters with about 3 billion active for each token. The Talker is a separate 3-billion-parameter MoE component. For text-only use, Qwen exposes &lt;code&gt;model.disable_talker()&lt;/code&gt;, allowing the speech-generation component to be omitted.&lt;/p&gt;

&lt;p&gt;This separation matters. I am not trying to teach the model a Barbadian voice, and I do not have a labelled corpus of Barbadian audio and transcripts large enough to retrain its acoustic front end. I am trying to adapt the component that interprets context and chooses text.&lt;/p&gt;

&lt;p&gt;There is precedent inside Qwen's own work for treating these components separately. The Qwen3-Omni report describes distinct post-training pipelines for the Thinker and Talker, and its audio Captioner is produced by fine-tuning the Thinker for audio-to-text output. Our training objective is different, but the architectural boundary is intentional rather than a convenient hack.&lt;/p&gt;

&lt;h2&gt;
  
  
  Training The Thinker, Not The Talker
&lt;/h2&gt;

&lt;p&gt;We used domain-adaptive pretraining, usually shortened to DAPT.&lt;/p&gt;

&lt;p&gt;The idea is straightforward: take a model that has already been pretrained on broad data, then continue its language-modelling objective on unlabelled text from the target domain. Gururangan and colleagues' ACL 2020 paper &lt;a href="https://aclanthology.org/2020.acl-main.740/" rel="noopener noreferrer"&gt;Don't Stop Pretraining&lt;/a&gt; found that this second in-domain phase consistently improved downstream performance across several domains and resource levels.&lt;/p&gt;

&lt;p&gt;This was not instruction tuning. The newspaper chunks were not converted into question-and-answer pairs. We presented them as assistant-only continuation records and continued next-token training. The objective was to change what language and relationships the model finds probable, not to teach it a new chat format.&lt;/p&gt;

&lt;p&gt;We used &lt;a href="https://arxiv.org/abs/2106.09685" rel="noopener noreferrer"&gt;LoRA&lt;/a&gt; rather than updating every weight. LoRA freezes the original model and injects trainable low-rank matrices into selected transformer layers. That gives us a portable adapter rather than another complete copy of a very large model.&lt;/p&gt;

&lt;p&gt;Our LoRA configuration was:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Setting&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Rank&lt;/td&gt;
&lt;td&gt;64&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Alpha&lt;/td&gt;
&lt;td&gt;128&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dropout&lt;/td&gt;
&lt;td&gt;0.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Attention targets&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;q_proj&lt;/code&gt;, &lt;code&gt;k_proj&lt;/code&gt;, &lt;code&gt;v_proj&lt;/code&gt;, &lt;code&gt;o_proj&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MLP targets&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;gate_proj&lt;/code&gt;, &lt;code&gt;up_proj&lt;/code&gt;, &lt;code&gt;down_proj&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Base precision&lt;/td&gt;
&lt;td&gt;bfloat16&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Context length&lt;/td&gt;
&lt;td&gt;4,096 tokens&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Batch size&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gradient accumulation&lt;/td&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Learning rate&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1e-4&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scheduler&lt;/td&gt;
&lt;td&gt;cosine, 3% warm-up&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The modality encoders and aligner were frozen. The Talker was disabled. Only LoRA parameters associated with the Thinker's language model were trained.&lt;/p&gt;

&lt;p&gt;One unusually specific setting was &lt;code&gt;lora_dropout=0.0&lt;/code&gt;. Qwen3-Omni uses PEFT parameter wrappers for some MoE parameters, and those wrappers reject non-zero LoRA dropout. The default in our training stack was 0.05, so this was one of those small details that stops an expensive run before it has really begun.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building The Corpus
&lt;/h2&gt;

&lt;p&gt;The source material available for this first run was 1,286 extracted editions of the &lt;em&gt;Barbados Advocate&lt;/em&gt;, spanning 2013 to 2023. This was a substantial working corpus, but it was not the complete archive. PDF extraction and cleaning were still running when we started training.&lt;/p&gt;

&lt;p&gt;This gave us something general web text does not: sustained coverage of local life over time. The archive contains politics, schools, trade unions, public health, sport, music, community events, weather, regional affairs, court reports, business and the names of people and places that rarely occur in global datasets.&lt;/p&gt;

&lt;p&gt;The raw source was PDF, so the preparation pipeline mattered as much as the training command.&lt;/p&gt;

&lt;p&gt;We used Docling with full-page OCR to extract text. We then:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Normalised punctuation, HTML entities, Unicode and whitespace.&lt;/li&gt;
&lt;li&gt;Removed selected boilerplate patterns, page-continuation markers, standalone
labelled contact lines, bylines and obvious layout noise.&lt;/li&gt;
&lt;li&gt;Rejected prose dominated by isolated OCR characters.&lt;/li&gt;
&lt;li&gt;Preserved useful article headings and paragraph boundaries.&lt;/li&gt;
&lt;li&gt;Combined the cleaned material into chunks targeting 250 to 1,000 words.&lt;/li&gt;
&lt;li&gt;Serialised each chunk as an assistant-only JSONL training record.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;On the GPU server, we applied a second validation pass using Qwen's tokenizer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;validate every record and require non-empty assistant text&lt;/li&gt;
&lt;li&gt;deduplicate exact content using SHA-256&lt;/li&gt;
&lt;li&gt;discard records shorter than 256 tokens or longer than 4,096&lt;/li&gt;
&lt;li&gt;length-sort the remaining records&lt;/li&gt;
&lt;li&gt;create a deterministic 2% evaluation split&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The resulting numbers were:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Corpus stage&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;JSONL shards&lt;/td&gt;
&lt;td&gt;1,286&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Valid input records&lt;/td&gt;
&lt;td&gt;49,322&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Exact duplicates removed&lt;/td&gt;
&lt;td&gt;150&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Below 256 tokens&lt;/td&gt;
&lt;td&gt;256&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Above 4,096 tokens&lt;/td&gt;
&lt;td&gt;17&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Training records&lt;/td&gt;
&lt;td&gt;47,921&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Evaluation records&lt;/td&gt;
&lt;td&gt;978&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Training tokens&lt;/td&gt;
&lt;td&gt;51,647,254&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The source JSONL snapshot occupied about 238 MB. These figures describe the first run, not the final planned corpus. The corpus remains private and is not redistributed. The trained adapter is public.&lt;/p&gt;

&lt;p&gt;There are limitations in the data. It is formal newspaper language, not spontaneous Bajan speech. OCR is never perfect. Newspaper coverage reflects editorial choices and historical bias. We also trained only on the extracted &lt;em&gt;Barbados Advocate&lt;/em&gt; snapshot, without adding a separate general-language “wash”. The newspaper itself contains regional and international reporting, but this one-source mixture may still encourage specialisation at the expense of some general capability.&lt;/p&gt;

&lt;p&gt;That last trade-off shows up in the benchmark.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Training Run
&lt;/h2&gt;

&lt;p&gt;I rented a single NVIDIA H200 with 141 GB of memory through Prime Intellect. The successful machine was an on-demand Nebius instance with 16 vCPUs, 200 GB of system RAM and a 1.5 TB boot disk.&lt;/p&gt;

&lt;p&gt;The model used almost all of it.&lt;/p&gt;

&lt;p&gt;A two-step smoke test peaked at 138.1 GB of GPU memory. That left roughly 3 GB of headroom, so batch size 1 with 16 gradient-accumulation steps was not merely conservative. It was the practical ceiling at a 4,096-token context length.&lt;/p&gt;

&lt;p&gt;Training used PyTorch 2.7.1, Transformers 5.8.1, ms-swift 4.4.2, FlashAttention 2 and bfloat16. Checkpoints were written every 250 optimiser steps, with automatic resume and a GPU-hour budget guard around the process.&lt;/p&gt;

&lt;p&gt;We stopped after checkpoint 500 of a planned 801 steps, completing about 62% of the intended schedule. This was the first full training attempt, not a converged final model. At that point:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Training loss&lt;/td&gt;
&lt;td&gt;2.0749&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Evaluation loss&lt;/td&gt;
&lt;td&gt;2.1271&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Evaluation token accuracy&lt;/td&gt;
&lt;td&gt;0.5358&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The adapter is available on Hugging Face as &lt;a href="https://huggingface.co/hammertoe/Qwen3-Omni-30B-A3B-Barbados-LoRA" rel="noopener noreferrer"&gt;hammertoe/Qwen3-Omni-30B-A3B-Barbados-LoRA&lt;/a&gt;. It is tied to base revision &lt;code&gt;26291f793822fb6be9555850f06dfe95f2d7e695&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Benchmark That Nearly Lied
&lt;/h2&gt;

&lt;p&gt;The first benchmark run reported identical results for the base model and the adapter. The held-out perplexity was identical too.&lt;/p&gt;

&lt;p&gt;That looked like a disappointing but perfectly plausible outcome: perhaps the adapter had learned nothing useful.&lt;/p&gt;

&lt;p&gt;It was actually an inference bug.&lt;/p&gt;

&lt;p&gt;Qwen3-Omni's adapter keys are rooted beneath the complete model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;base_model.model.thinker.model.layers.0.self_attn.q_proj.lora_B.weight
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We had attached PEFT directly to &lt;code&gt;model.thinker&lt;/code&gt;. PEFT returned a model without raising an obvious error, but the intended projection layers remained ordinary linear layers. The adapter was not active.&lt;/p&gt;

&lt;p&gt;The correct sequence was to attach PEFT to the complete Omni model and only then select its adapted Thinker:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Qwen3OmniMoeForConditionalGeneration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_pretrained&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;base_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;dtype&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bfloat16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;device_map&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;auto&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;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;disable_talker&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;adapted_root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PeftModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_pretrained&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;adapter_path&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;eval&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;adapted_thinker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;adapted_root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;thinker&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We added an activation gate before trusting another result. It checks that a target projection is a PEFT LoRA layer, that the loaded adapter weights have a non-zero norm, and that base and adapted outputs differ on identical input.&lt;/p&gt;

&lt;p&gt;There was another compatibility wrinkle. ms-swift 4.4.2 requires PEFT below 0.20 for training, but PEFT 0.19.1 could not load this Qwen Omni adapter with Transformers 5.8.1 because of an incompatible &lt;code&gt;WeightConverter&lt;/code&gt; call. The working inference stack used PEFT 0.20.0 in a separate environment. Keeping training and inference environments separate turned out to be much safer than trying to make one dependency set serve both jobs.&lt;/p&gt;

&lt;p&gt;For “The Crop Over festival in Barbados”, the loss changed from &lt;code&gt;3.5603&lt;/code&gt; to &lt;code&gt;3.1089&lt;/code&gt;. That did not tell us whether the adapter was good, but it finally proved that we were measuring the adapter.&lt;/p&gt;

&lt;p&gt;This bit took more work than I expected. It was also a useful reminder that “the checkpoint loaded” is not the same as “the checkpoint affected inference”.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Barbados Knowledge Benchmark
&lt;/h2&gt;

&lt;p&gt;We built a small paired benchmark of 60 four-choice completion probes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;20 local probes&lt;/li&gt;
&lt;li&gt;20 rare-local probes&lt;/li&gt;
&lt;li&gt;20 general-knowledge controls&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The 60 probes represent 30 facts. Every fact has a canonical question and an independently worded paraphrase. Answer positions are balanced across all four choices.&lt;/p&gt;

&lt;p&gt;Rather than ask the model to emit a letter, we score each candidate completion using its mean token log-probability. For each probe, the margin is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;score(correct completion) - score(strongest incorrect completion)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A positive margin is correct. A negative margin is wrong. Changes in margin also show whether the model moved towards the answer without crossing the decision boundary.&lt;/p&gt;

&lt;p&gt;The benchmark then compares base and adapter results as a pair. We report accuracy, margin changes, wins and losses, strict fact families, and a control-adjusted local margin. A strict fact family only passes when both wordings are correct.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Results
&lt;/h2&gt;

&lt;p&gt;These are preliminary results from that partial first run and partial corpus. They are useful for deciding whether the approach is worth continuing, not for claiming a finished Barbados model.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Track&lt;/th&gt;
&lt;th&gt;N&lt;/th&gt;
&lt;th&gt;Base accuracy&lt;/th&gt;
&lt;th&gt;Adapter accuracy&lt;/th&gt;
&lt;th&gt;Delta&lt;/th&gt;
&lt;th&gt;Margin delta&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Local&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;td&gt;55.0%&lt;/td&gt;
&lt;td&gt;65.0%&lt;/td&gt;
&lt;td&gt;+10.0 points&lt;/td&gt;
&lt;td&gt;+0.247&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rare local&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;td&gt;45.0%&lt;/td&gt;
&lt;td&gt;60.0%&lt;/td&gt;
&lt;td&gt;+15.0 points&lt;/td&gt;
&lt;td&gt;+0.198&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;General controls&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;td&gt;90.0%&lt;/td&gt;
&lt;td&gt;85.0%&lt;/td&gt;
&lt;td&gt;-5.0 points&lt;/td&gt;
&lt;td&gt;-0.344&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Overall&lt;/td&gt;
&lt;td&gt;60&lt;/td&gt;
&lt;td&gt;63.3%&lt;/td&gt;
&lt;td&gt;70.0%&lt;/td&gt;
&lt;td&gt;+6.7 points&lt;/td&gt;
&lt;td&gt;+0.034&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Pooling the local and rare-local probes, then subtracting the control margin delta, gave an exploratory difference-in-differences estimate of &lt;code&gt;+0.567&lt;/code&gt;. Across the 20 Barbados fact families, strict performance improved from 7 to 11. Four families moved from failing to passing, with no strict Barbados family moving from fully correct to fully wrong. The general controls declined from 8/10 to 7/10 strict families.&lt;/p&gt;

&lt;p&gt;The sample is small. A descriptive percentile bootstrap over the 20 local probe wordings produced an interval of &lt;code&gt;-0.399&lt;/code&gt; to &lt;code&gt;+0.822&lt;/code&gt;. Because each fact contributes two related wordings, this probe-level interval should not be treated as a confirmatory fact-level confidence interval. This is evidence of movement, not a definitive estimate of effect size.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Category Breakdown Was More Interesting
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Category&lt;/th&gt;
&lt;th&gt;N&lt;/th&gt;
&lt;th&gt;Base&lt;/th&gt;
&lt;th&gt;Adapter&lt;/th&gt;
&lt;th&gt;Accuracy delta&lt;/th&gt;
&lt;th&gt;Margin delta&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Cricket and sport&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;33.3%&lt;/td&gt;
&lt;td&gt;33.3%&lt;/td&gt;
&lt;td&gt;0.0&lt;/td&gt;
&lt;td&gt;+0.310&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Culture and music&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;33.3%&lt;/td&gt;
&lt;td&gt;33.3%&lt;/td&gt;
&lt;td&gt;0.0&lt;/td&gt;
&lt;td&gt;+0.074&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;History&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;66.7%&lt;/td&gt;
&lt;td&gt;66.7%&lt;/td&gt;
&lt;td&gt;0.0&lt;/td&gt;
&lt;td&gt;+0.503&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;General controls&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;td&gt;90.0%&lt;/td&gt;
&lt;td&gt;85.0%&lt;/td&gt;
&lt;td&gt;-5.0&lt;/td&gt;
&lt;td&gt;-0.344&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;People and institutions&lt;/td&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;td&gt;50.0%&lt;/td&gt;
&lt;td&gt;75.0%&lt;/td&gt;
&lt;td&gt;+25.0&lt;/td&gt;
&lt;td&gt;+0.347&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Places and geography&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;66.7%&lt;/td&gt;
&lt;td&gt;83.3%&lt;/td&gt;
&lt;td&gt;+16.7&lt;/td&gt;
&lt;td&gt;-0.327&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Here, &lt;code&gt;N&lt;/code&gt; counts probe wordings rather than independent facts. A category with six probes contains three facts, so one answer changes its accuracy by 16.7 percentage points. The category table is diagnostic, not a stable leaderboard.&lt;/p&gt;

&lt;p&gt;People and institutions produced the clearest improvement. Four probes changed from wrong to correct, with no correct-to-wrong flips:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Queen Elizabeth Hospital opening: 1958 became the correct 1964&lt;/li&gt;
&lt;li&gt;Barbados Workers' Union formation: 1938 became the correct 1941&lt;/li&gt;
&lt;li&gt;free secondary education: 1966 became the correct 1962&lt;/li&gt;
&lt;li&gt;SJPP: “St. James Parish Polytechnic” became the correct “Samuel Jackman Prescod Polytechnic”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Three of those became strict two-wording transitions from failing to passing. The Barbados Workers' Union fact changed on only one wording.&lt;/p&gt;

&lt;p&gt;History showed another useful pattern. Accuracy did not change, but the average margin improved by &lt;code&gt;+0.503&lt;/code&gt;. The model became more confident about the first Parliament year and moved much closer to the national motto, while still not ranking it first. A binary accuracy score would hide that movement.&lt;/p&gt;

&lt;p&gt;Places and geography is the warning against reading category percentages too quickly. Accuracy improved by one net probe, but average margin declined. The adapter corrected a land-area question and one wording of the UWI Cave Hill question, then broke the other wording of the same Cave Hill fact. That is wording sensitivity, not robust geographical understanding.&lt;/p&gt;

&lt;p&gt;Culture and cricket mostly showed movement without new correct answers. The model got closer on some obscure details while losing confidence on facts it already knew. Again, useful diagnostic information, but not a product result.&lt;/p&gt;

&lt;p&gt;The control regression came from one answer flip: the SI unit of catalytic activity, &lt;code&gt;katal&lt;/code&gt;, moved from correct to incorrect. Several controls remained correct but lost margin. With only 20 control probes, this is not evidence of a broad collapse, but it is consistent with the specialisation risk we wanted the controls to expose.&lt;/p&gt;

&lt;h2&gt;
  
  
  What This Benchmark Is
&lt;/h2&gt;

&lt;p&gt;I think this benchmark is best described as an &lt;strong&gt;archive-authored Barbados knowledge probe&lt;/strong&gt; for an early checkpoint.&lt;/p&gt;

&lt;p&gt;It suggests that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the adapter is active&lt;/li&gt;
&lt;li&gt;continued pretraining changed scores in a Barbados-specific direction&lt;/li&gt;
&lt;li&gt;some Barbados fact probes became more robust across paraphrases&lt;/li&gt;
&lt;li&gt;the strongest gains were around named institutions and their history&lt;/li&gt;
&lt;li&gt;there may be a small general-capability cost&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is worthwhile. Before this benchmark, we did not know whether the training had done anything beyond lowering next-token loss.&lt;/p&gt;

&lt;h2&gt;
  
  
  What This Benchmark Is Not
&lt;/h2&gt;

&lt;p&gt;It is not an audio benchmark.&lt;/p&gt;

&lt;p&gt;Knowing that Queen Elizabeth Hospital opened in 1964 does not demonstrate that the model can hear “Queen Elizabeth Hospital” through a Barbadian accent, a poor microphone or music in the background. Years are particularly weak proxies for transcription.&lt;/p&gt;

&lt;p&gt;It is not a broad test of cultural understanding either. The benchmark covers named people, institutions, dates, places and selected events. It does not test Bajan vocabulary, informal grammar, pragmatics, code-switching, pronunciation or whether the model understands an implied local reference in conversation.&lt;/p&gt;

&lt;p&gt;The questions were authored from the broader newspaper archive, but we did not resolve their cited source records against the exact packed training and evaluation split used for this run. At least one benchmark source sits outside the 2013 to 2023 snapshot. That means this run cannot establish whether every changed answer came from direct exposure, indirect domain adaptation, or knowledge already present in the base model. It is not a clean test of unseen generalisation either.&lt;/p&gt;

&lt;p&gt;So the honest conclusion is not “we improved Barbadian transcription by 15%”. We did not measure that.&lt;/p&gt;

&lt;p&gt;The conclusion is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In a preliminary first run using a partially extracted corpus, text-only DAPT&lt;br&gt;
produced higher scores on a small set of Barbados questions, with the clearest&lt;br&gt;
difference around people and institutions. The exact relationship between&lt;br&gt;
those questions and the packed training split was not resolved. Whether the&lt;br&gt;
effect holds after full training, generalises to held-out local material, or&lt;br&gt;
produces more accurate audio transcription remain open questions.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Why I Still Think It Could Help Transcription
&lt;/h2&gt;

&lt;p&gt;Qwen3-Omni's Thinker is where multimodal evidence becomes text. Audio reaches it through the AuT encoder and modality alignment layers. We have left those acoustic components unchanged, but adjusted the language model that interprets their representations and chooses the output tokens.&lt;/p&gt;

&lt;p&gt;The intended effect is narrow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ambiguous audio + stronger Barbados prior -&amp;gt; better local word choice
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It should not make the model hear an accent better. It may make it more likely to choose &lt;code&gt;Kensington Oval&lt;/code&gt; over a globally common but locally implausible alternative. It may help preserve the full name &lt;code&gt;Samuel Jackman Prescod Polytechnic&lt;/code&gt;. It may resolve a phrase because it understands that a person, institution and place regularly occur together in Barbados reporting.&lt;/p&gt;

&lt;p&gt;But there is an equal and opposite risk. A strong prior can override clear acoustic evidence and hallucinate familiar local entities. The decline in our general controls is a reason to test that carefully, not hand-wave it away.&lt;/p&gt;

&lt;p&gt;This is also where newspaper text may reach its limit. It contains a great deal of local context, but it does not represent spontaneous radio speech. If the problem is pronunciation, accent or code-switching, text-only DAPT is unlikely to be enough. We may eventually need paired local audio and transcripts, or a hybrid approach combining a local lexicon, retrieval and model adaptation.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Next Benchmark Has To Be Audio
&lt;/h2&gt;

&lt;p&gt;The next evaluation will compare the base and adapted models on exactly the same manually transcribed Barbados audio.&lt;/p&gt;

&lt;p&gt;It needs more than one aggregate word error rate. We plan to measure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ordinary word error rate and character error rate&lt;/li&gt;
&lt;li&gt;named-entity error rate&lt;/li&gt;
&lt;li&gt;local-term recall&lt;/li&gt;
&lt;li&gt;accuracy for numbers and dates&lt;/li&gt;
&lt;li&gt;substitutions, deletions and hallucinated entities&lt;/li&gt;
&lt;li&gt;performance by speaker, noise level and content type&lt;/li&gt;
&lt;li&gt;general English audio as a regression control&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The test set should include news, interviews, radio phone-ins, sport, Crop Over coverage, government speech and informal conversation. It should also contain minimal pairs such as &lt;code&gt;Kensington&lt;/code&gt; versus &lt;code&gt;Kingston&lt;/code&gt;, &lt;code&gt;Cave Hill&lt;/code&gt; versus &lt;code&gt;Codrington&lt;/code&gt;, and &lt;code&gt;Prescod&lt;/code&gt; versus &lt;code&gt;Prescott&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Most importantly, none of its reference transcripts should appear in the text training corpus.&lt;/p&gt;

&lt;p&gt;If the adapter reduces errors on local entities without increasing hallucinations or damaging general transcription, then we will have something much closer to the result we actually care about.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where We Are Now
&lt;/h2&gt;

&lt;p&gt;So far, we have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;prepared a first 51.6-million-token Barbados newspaper snapshot&lt;/li&gt;
&lt;li&gt;adapted the Qwen3-Omni Thinker with a rank-64 LoRA&lt;/li&gt;
&lt;li&gt;completed 500 of 801 planned optimiser steps on a single H200&lt;/li&gt;
&lt;li&gt;published the adapter on Hugging Face&lt;/li&gt;
&lt;li&gt;built a paired Barbados knowledge benchmark&lt;/li&gt;
&lt;li&gt;observed higher scores on a preliminary Barbados knowledge probe and a small control regression&lt;/li&gt;
&lt;li&gt;fixed an inference bug that initially made the benchmark lie to us&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We have not yet:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;completed the first planned training schedule&lt;/li&gt;
&lt;li&gt;finished extracting and preparing the full newspaper corpus&lt;/li&gt;
&lt;li&gt;validated improved transcription on Barbados audio&lt;/li&gt;
&lt;li&gt;shown improved accent or dialect recognition&lt;/li&gt;
&lt;li&gt;established broad cultural understanding&lt;/li&gt;
&lt;li&gt;completed and validated the planned 4-bit Apple Silicon deployment&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That may sound like a cautious ending. I think it is a useful one.&lt;/p&gt;

&lt;p&gt;The experiment has moved from “perhaps local text could help” to “an early, partially trained model behaves differently on a small set of local questions”. The next run will use more of the archive and complete the training schedule. Then we need held-out text and audio benchmarks to find out whether that change is useful.&lt;/p&gt;

&lt;p&gt;Stay tuned. The word-error-rate table is the one I really want to publish.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Qwen Team. &lt;a href="https://arxiv.org/abs/2509.17765" rel="noopener noreferrer"&gt;Qwen3-Omni Technical Report&lt;/a&gt;, 2025.&lt;/li&gt;
&lt;li&gt;Suchin Gururangan et al. &lt;a href="https://aclanthology.org/2020.acl-main.740/" rel="noopener noreferrer"&gt;Don't Stop Pretraining: Adapt Language Models to Domains and Tasks&lt;/a&gt;, ACL 2020.&lt;/li&gt;
&lt;li&gt;Edward J. Hu et al. &lt;a href="https://arxiv.org/abs/2106.09685" rel="noopener noreferrer"&gt;LoRA: Low-Rank Adaptation of Large Language Models&lt;/a&gt;, 2021.&lt;/li&gt;
&lt;li&gt;Golan Pundak et al. &lt;a href="https://arxiv.org/abs/1808.02480" rel="noopener noreferrer"&gt;Deep Context: End-to-End Contextual Speech Recognition&lt;/a&gt;, 2018.&lt;/li&gt;
&lt;li&gt;Duc Le et al. &lt;a href="https://arxiv.org/abs/2104.02194" rel="noopener noreferrer"&gt;Contextualized Streaming End-to-End Speech Recognition with Trie-Based Deep Biasing and Shallow Fusion&lt;/a&gt;, Interspeech 2021.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://huggingface.co/Qwen/Qwen3-Omni-30B-A3B-Instruct" rel="noopener noreferrer"&gt;Qwen3-Omni-30B-A3B-Instruct on Hugging Face&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://huggingface.co/hammertoe/Qwen3-Omni-30B-A3B-Barbados-LoRA" rel="noopener noreferrer"&gt;Qwen3-Omni Barbados LoRA on Hugging Face&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>barbados</category>
      <category>llm</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>Moving WeOutside246 from GPT-5 to local models on a base M4 Mac Mini</title>
      <dc:creator>Matt Hamilton</dc:creator>
      <pubDate>Mon, 06 Apr 2026 11:29:57 +0000</pubDate>
      <link>https://dev.to/hammertoe/moving-weoutside246-from-gpt-5-to-local-models-on-a-base-m4-mac-mini-2mb5</link>
      <guid>https://dev.to/hammertoe/moving-weoutside246-from-gpt-5-to-local-models-on-a-base-m4-mac-mini-2mb5</guid>
      <description>&lt;p&gt;So, I've been spending a lot of time recently trying to answer a question that I think a lot of indie AI builders are going to hit sooner rather than later:&lt;/p&gt;

&lt;p&gt;Can I stop renting intelligence from a hyperscaler and just run the thing myself?&lt;/p&gt;

&lt;p&gt;In my case the project is &lt;a href="https://weoutside246.com/" rel="noopener noreferrer"&gt;WeOutside246&lt;/a&gt;, an autonomous agent I built to track the pulse of Barbados. It follows more than 900 Instagram accounts, reads thousands of posts, looks at images, and tries to work out whether something is an upcoming event on the island or just noise. And by noise I mean all the things that look a bit event-ish but are not actually useful for an events listing site: recaps, giveaway posts, sports fixtures, lifestyle shots, throwbacks, posts from other islands, and so on.&lt;/p&gt;

&lt;p&gt;This is very much not a toy problem.&lt;/p&gt;

&lt;p&gt;The small things matter here. A model that confuses a recap from last weekend with a fete happening next Friday is not just slightly wrong. It makes the site worse.&lt;/p&gt;

&lt;p&gt;So this post is a technical write-up of what I did, what I learned, and how the latest generation of local models performed when I moved evaluation onto a base-spec Mac Mini M4 with 16GB of RAM.&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.amazonaws.com%2Fuploads%2Farticles%2F260gdf0pdoxvham9o38i.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.amazonaws.com%2Fuploads%2Farticles%2F260gdf0pdoxvham9o38i.jpg" alt="WeOutside246.com homepage showing recent events" width="800" height="731"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;As some of you may know, WeOutside246 is an autonomous system for discovering events in Barbados from Instagram posts.&lt;/p&gt;

&lt;p&gt;At a high level the pipeline looks like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Follow hundreds of relevant Barbados accounts&lt;/li&gt;
&lt;li&gt;Collect post text, metadata, and images&lt;/li&gt;
&lt;li&gt;Ask a model to classify whether the post is an upcoming Barbados entertainment event&lt;/li&gt;
&lt;li&gt;Extract structured fields such as event name, date, venue, artists, and type&lt;/li&gt;
&lt;li&gt;Deduplicate and rank posters&lt;/li&gt;
&lt;li&gt;Publish the results to the site&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The core extraction problem sounds simple until you look at real data.&lt;/p&gt;

&lt;p&gt;The model needs to distinguish between:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;an actual upcoming fete in Barbados&lt;/li&gt;
&lt;li&gt;a recap of a fete that already happened&lt;/li&gt;
&lt;li&gt;a cruise poster for St. Lucia with a Barbadian DJ on it&lt;/li&gt;
&lt;li&gt;a sporting event that looks like nightlife marketing&lt;/li&gt;
&lt;li&gt;a giveaway post that references an event but is not itself an event listing&lt;/li&gt;
&lt;li&gt;a lifestyle post with hashtags that smell like an event but no actual details&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And it has to do that from a combination of caption text and image understanding.&lt;/p&gt;

&lt;p&gt;Until recently I was relying heavily on frontier hosted models for this. That works. But having said that, it is expensive, and if you are running an always-on ingestion system against thousands of posts, those costs become structural rather than occasional.&lt;/p&gt;

&lt;p&gt;I also wanted to reduce the environmental footprint. If I can do the same work on a tiny local machine sipping power on my desk rather than a large hosted inference stack somewhere in a data centre, I think that is worth doing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why a Mac Mini M4?
&lt;/h2&gt;

&lt;p&gt;I've been running these evaluations on a base-spec Mac Mini M4 with 16GB unified memory.&lt;/p&gt;

&lt;p&gt;That is very much the point.&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.amazonaws.com%2Fuploads%2Farticles%2Ffxqyw0s4xhyn5u0lxzeh.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.amazonaws.com%2Fuploads%2Farticles%2Ffxqyw0s4xhyn5u0lxzeh.jpg" alt="Mac Mini setup on the floor for testing" width="800" height="1066"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I did not want a benchmark based on a giant workstation or a rented GPU box because that would miss the whole exercise. The question I cared about was:&lt;/p&gt;

&lt;p&gt;Can a normal, relatively inexpensive, very power-efficient machine do useful multimodal event extraction work locally?&lt;/p&gt;

&lt;p&gt;The Mac Mini is attractive for a few reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;low idle and working power draw&lt;/li&gt;
&lt;li&gt;tiny footprint&lt;/li&gt;
&lt;li&gt;quiet&lt;/li&gt;
&lt;li&gt;unified memory makes local model serving on Apple Silicon surprisingly capable&lt;/li&gt;
&lt;li&gt;easy to leave running 24/7 for a self-hosted pipeline&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the motivation here was not just cost. It was cost and energy together.&lt;/p&gt;

&lt;p&gt;Hosted frontier models are brilliant, and I still use them in parts of the workflow, but I don't necessarily want to burn that much money and energy on the classification layer forever.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Models
&lt;/h2&gt;

&lt;p&gt;I tested a mix of Gemma 4 and Qwen 3.5 models, both dense and MoE, plus one private fine-tuned Gemma 4B variant.&lt;/p&gt;

&lt;p&gt;The public models were:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://huggingface.co/mlx-community/gemma-4-26b-a4b-it-4bit" rel="noopener noreferrer"&gt;Gemma 4 26B A4B Instruct 4-bit (MLX Community)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://huggingface.co/mlx-community/gemma-4-e4b-it-4bit" rel="noopener noreferrer"&gt;Gemma 4 4B E4B Instruct 4-bit (MLX Community)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://huggingface.co/mlx-community/Qwen3.5-35B-A3B-4bit" rel="noopener noreferrer"&gt;Qwen 3.5 35B A3B 4-bit (MLX Community)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://huggingface.co/mlx-community/Qwen3.5-9B-MLX-4bit" rel="noopener noreferrer"&gt;Qwen 3.5 9B 4-bit (MLX Community)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://huggingface.co/mlx-community/Qwen3.5-4B-MLX-4bit" rel="noopener noreferrer"&gt;Qwen 3.5 4B 4-bit (MLX Community)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I also tested a private fine-tuned Gemma 4B model trained on my own reference set. &lt;/p&gt;

&lt;h2&gt;
  
  
  The Evaluation Setup
&lt;/h2&gt;

&lt;p&gt;One of the things I wanted to avoid was the classic "I eyeballed a few examples and it seemed good" trap.&lt;/p&gt;

&lt;p&gt;So I built a reference dataset and local evaluation harness.&lt;/p&gt;

&lt;p&gt;The process looked like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use GPT-5 to generate high-quality structured reference outputs for a set of real posts&lt;/li&gt;
&lt;li&gt;Manually review and correct the labels where necessary&lt;/li&gt;
&lt;li&gt;Run local models against the same inputs&lt;/li&gt;
&lt;li&gt;Compare &lt;code&gt;isEvent&lt;/code&gt; classification and structured extraction quality&lt;/li&gt;
&lt;li&gt;Use GPT-5 again as a judge for qualitative scoring of the full output&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That gave me two lenses:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;simple metrics: accuracy, precision, recall, false positives, false negatives&lt;/li&gt;
&lt;li&gt;judge metrics: a GPT-5 score for how good the full structured answer was&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The simple metrics mattered most for the event gate. If the model gets &lt;code&gt;isEvent&lt;/code&gt; wrong, the rest is almost irrelevant.&lt;/p&gt;

&lt;p&gt;But the judge scores were useful because they told me something about the shape of the errors. Two models can have similar classification accuracy and still differ a lot in extraction quality, reasoning quality, or schema compliance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cleaning the Gold Standard
&lt;/h2&gt;

&lt;p&gt;This bit took more work than I expected.&lt;/p&gt;

&lt;p&gt;I started by treating the GPT-5 generated reference set as a gold standard. It turned out to be more like a gold-plated standard. Very good, but not perfect.&lt;/p&gt;

&lt;p&gt;Once I began running the local models against it, I found a bunch of cases where the references themselves needed correction. That included:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;recap posts marked as upcoming events&lt;/li&gt;
&lt;li&gt;sporting events marked as entertainment events&lt;/li&gt;
&lt;li&gt;giveaway posts treated as event listings&lt;/li&gt;
&lt;li&gt;posts with no explicit date that should not have passed the gate&lt;/li&gt;
&lt;li&gt;posts from outside Barbados that looked plausible at first glance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In total I corrected dozens of labels in the reference and fine-tuning data. That was frustrating, but also useful. The models were forcing me to sharpen the rules, not just evaluate them.&lt;/p&gt;

&lt;p&gt;That led to a stricter prompt with explicit rules such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;date is mandatory&lt;/li&gt;
&lt;li&gt;recap language means &lt;code&gt;isEvent=false&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;sports and giveaways are excluded&lt;/li&gt;
&lt;li&gt;the event must actually be in Barbados&lt;/li&gt;
&lt;li&gt;venue is preferred, but I eventually relaxed that rule for dated event posts where venue is genuinely announced separately&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last point was an interesting one. I initially made venue mandatory. In practice, that was too strict for some real-world Caribbean event posts, particularly certain cruises, outdoor events, and posts where the date is locked in but the venue is released later.&lt;/p&gt;

&lt;p&gt;So the prompt evolved. And the reference data evolved with it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Results
&lt;/h2&gt;

&lt;p&gt;These are the latest full 200-sample runs on the cleaned reference set.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Architecture&lt;/th&gt;
&lt;th&gt;Accuracy&lt;/th&gt;
&lt;th&gt;Precision&lt;/th&gt;
&lt;th&gt;Recall&lt;/th&gt;
&lt;th&gt;F1&lt;/th&gt;
&lt;th&gt;TP&lt;/th&gt;
&lt;th&gt;TN&lt;/th&gt;
&lt;th&gt;FP&lt;/th&gt;
&lt;th&gt;FN&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Gemma 4 26B A4B&lt;/td&gt;
&lt;td&gt;MoE&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;96.0%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;86.0%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;100.0%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;92.5%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;49&lt;/td&gt;
&lt;td&gt;143&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Qwen 3.5 9B&lt;/td&gt;
&lt;td&gt;Dense&lt;/td&gt;
&lt;td&gt;92.5%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;94.7%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;76.6%&lt;/td&gt;
&lt;td&gt;84.7%&lt;/td&gt;
&lt;td&gt;36&lt;/td&gt;
&lt;td&gt;149&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Qwen 3.5 35B A3B&lt;/td&gt;
&lt;td&gt;MoE&lt;/td&gt;
&lt;td&gt;91.5%&lt;/td&gt;
&lt;td&gt;83.3%&lt;/td&gt;
&lt;td&gt;81.6%&lt;/td&gt;
&lt;td&gt;82.5%&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;td&gt;143&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemma 4 4B fine-tuned&lt;/td&gt;
&lt;td&gt;Dense&lt;/td&gt;
&lt;td&gt;88.0%&lt;/td&gt;
&lt;td&gt;71.9%&lt;/td&gt;
&lt;td&gt;83.7%&lt;/td&gt;
&lt;td&gt;77.4%&lt;/td&gt;
&lt;td&gt;41&lt;/td&gt;
&lt;td&gt;135&lt;/td&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemma 4 4B base&lt;/td&gt;
&lt;td&gt;Dense&lt;/td&gt;
&lt;td&gt;87.5%&lt;/td&gt;
&lt;td&gt;70.0%&lt;/td&gt;
&lt;td&gt;85.7%&lt;/td&gt;
&lt;td&gt;77.1%&lt;/td&gt;
&lt;td&gt;42&lt;/td&gt;
&lt;td&gt;133&lt;/td&gt;
&lt;td&gt;18&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Qwen 3.5 4B&lt;/td&gt;
&lt;td&gt;Dense&lt;/td&gt;
&lt;td&gt;86.0%&lt;/td&gt;
&lt;td&gt;86.8%&lt;/td&gt;
&lt;td&gt;76.7%&lt;/td&gt;
&lt;td&gt;81.5%&lt;/td&gt;
&lt;td&gt;33&lt;/td&gt;
&lt;td&gt;139&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;And here are the judge scores from GPT-5 on the 200-sample runs:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Accuracy&lt;/th&gt;
&lt;th&gt;Judge Avg&lt;/th&gt;
&lt;th&gt;Judge Median&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Qwen 3.5 35B A3B&lt;/td&gt;
&lt;td&gt;91.5%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;70.3&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;72.0&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemma 4 26B A4B&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;96.0%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;66.6&lt;/td&gt;
&lt;td&gt;68.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Qwen 3.5 9B&lt;/td&gt;
&lt;td&gt;92.5%&lt;/td&gt;
&lt;td&gt;64.3&lt;/td&gt;
&lt;td&gt;65.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Qwen 3.5 4B&lt;/td&gt;
&lt;td&gt;86.0%&lt;/td&gt;
&lt;td&gt;59.3&lt;/td&gt;
&lt;td&gt;61.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemma 4 4B base&lt;/td&gt;
&lt;td&gt;87.5%&lt;/td&gt;
&lt;td&gt;58.8&lt;/td&gt;
&lt;td&gt;60.5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemma 4 4B fine-tuned&lt;/td&gt;
&lt;td&gt;88.0%&lt;/td&gt;
&lt;td&gt;56.7&lt;/td&gt;
&lt;td&gt;58.0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  What Stood Out
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Gemma 4 26B A4B was the clear winner on the metric that matters most
&lt;/h3&gt;

&lt;p&gt;If your primary concern is "did we miss an actual event?" then Gemma 4 26B A4B was the standout.&lt;/p&gt;

&lt;p&gt;It had:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the best accuracy&lt;/li&gt;
&lt;li&gt;the best F1&lt;/li&gt;
&lt;li&gt;perfect recall in this run&lt;/li&gt;
&lt;li&gt;zero false negatives&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last number is the one that really grabbed me. Missing a real event is expensive for the product because it means the site is incomplete. Gemma 4 26B simply did not miss any of the true events in this dataset.&lt;/p&gt;

&lt;p&gt;It did still produce 8 false positives, so it is not flawless. But if I had to choose one local model today to sit behind the extraction gate, this would be the one.&lt;/p&gt;

&lt;h3&gt;
  
  
  Qwen 3.5 9B was surprisingly sharp
&lt;/h3&gt;

&lt;p&gt;Qwen 3.5 9B had the best precision at 94.7% with only 2 false positives.&lt;/p&gt;

&lt;p&gt;That means when it said something was an event, it was usually right.&lt;/p&gt;

&lt;p&gt;But the trade-off was recall. It missed 11 true events.&lt;/p&gt;

&lt;p&gt;So this is a more conservative classifier. Good if you hate false positives. Less good if your job is to make sure nobody misses a fete.&lt;/p&gt;

&lt;h3&gt;
  
  
  Qwen 3.5 35B A3B had the best judge score, but not the best event gate
&lt;/h3&gt;

&lt;p&gt;This was one of the more interesting outcomes.&lt;/p&gt;

&lt;p&gt;The GPT-5 judge liked Qwen 3.5 35B A3B the most overall. It scored 70.3 average versus 66.6 for Gemma 4 26B.&lt;/p&gt;

&lt;p&gt;I think what that means is that Qwen 35B often produced more polished or internally coherent structured outputs even when it was slightly worse on the raw event classification metrics.&lt;/p&gt;

&lt;p&gt;So if you optimise for "niceness" of extraction, Qwen 35B looks very strong.&lt;/p&gt;

&lt;p&gt;If you optimise for "did it miss a real event in Barbados?" then Gemma 26B still wins.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fine-tuning the 4B Gemma did not deliver the win I hoped for
&lt;/h3&gt;

&lt;p&gt;This one was humbling.&lt;/p&gt;

&lt;p&gt;The private fine-tuned Gemma 4B model scored 88.0%. The untuned Gemma 4B base model scored 87.5%.&lt;/p&gt;

&lt;p&gt;So yes, the fine-tuned version was technically a little better. But only just. And its judge score was actually worse than the base 4B.&lt;/p&gt;

&lt;p&gt;That suggests a few things may be going on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the base model was already quite capable&lt;/li&gt;
&lt;li&gt;the training set had historical label noise before I cleaned it properly&lt;/li&gt;
&lt;li&gt;the fine-tune may have overfit some patterns from the earlier prompt regime&lt;/li&gt;
&lt;li&gt;instruction-following from Gemma 4 is already doing a lot of the work&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is a good reminder that fine-tuning is not magic. If the prompt and labels are evolving quickly, it can be easier to degrade a small model than improve it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bigger was not always better inside the same family
&lt;/h3&gt;

&lt;p&gt;Qwen 3.5 9B outperformed Qwen 3.5 35B A3B on raw accuracy.&lt;/p&gt;

&lt;p&gt;That was a bit surprising.&lt;/p&gt;

&lt;p&gt;The 35B MoE variant had better judge scores and slightly better recall, but the 9B dense model was just more precise and ended up ahead on accuracy overall.&lt;/p&gt;

&lt;p&gt;So model family matters. Prompt compatibility matters. And architecture matters. It is not as simple as "pick the biggest one you can fit".&lt;/p&gt;

&lt;h2&gt;
  
  
  A Few Failure Modes
&lt;/h2&gt;

&lt;p&gt;Looking through the false positives and false negatives was one of the most useful parts of the process.&lt;/p&gt;

&lt;p&gt;Some of the recurring failure modes were:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;hallucinated dates from partial cues in the image&lt;/li&gt;
&lt;li&gt;treating recap albums as future events&lt;/li&gt;
&lt;li&gt;failing to apply the Barbados-only rule consistently&lt;/li&gt;
&lt;li&gt;being overconfident on lifestyle posts with event-ish hashtags&lt;/li&gt;
&lt;li&gt;treating giveaways and ancillary promos as primary event posts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One nice thing about using a local model here is that once you can categorise the failure mode, you can usually do one of three things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;tighten the prompt&lt;/li&gt;
&lt;li&gt;fix the reference labels&lt;/li&gt;
&lt;li&gt;accept the trade-off and pick the model whose mistakes you dislike the least&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last one is important. There is no perfect model here. There is only the model whose mistakes fit the product best.&lt;/p&gt;

&lt;p&gt;For WeOutside246, false negatives are especially painful because they mean a real event just never appears. So I am more willing to tolerate some false positives than I am to miss a legitimate Barbados event.&lt;/p&gt;

&lt;h2&gt;
  
  
  What This Means in Practice
&lt;/h2&gt;

&lt;p&gt;I think the biggest takeaway is this:&lt;/p&gt;

&lt;p&gt;You can now do serious multimodal extraction work locally on a tiny, consumer-grade Apple Silicon machine.&lt;/p&gt;

&lt;p&gt;Not perfectly. Not for every workload. But absolutely well enough to make it useful for a real product.&lt;/p&gt;

&lt;p&gt;That feels like a step change.&lt;/p&gt;

&lt;p&gt;Even a few months ago, I would have assumed this kind of pipeline needed to stay glued to frontier hosted models for the foreseeable future. Now I think the picture is much more nuanced.&lt;/p&gt;

&lt;p&gt;For WeOutside246, the likely shape of the system going forward is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;use local models for the bulk event extraction and classification work&lt;/li&gt;
&lt;li&gt;keep frontier models for higher-value judging, dataset generation, and perhaps some of the harder consolidation tasks&lt;/li&gt;
&lt;li&gt;continue refining prompts and evaluation as the content distribution changes over time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So this is not me saying hosted models are obsolete. Far from it.&lt;/p&gt;

&lt;p&gt;It is me saying that the boundary has moved. And for small products, side projects, and self-funded tools, that is a very big deal.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next Steps
&lt;/h2&gt;

&lt;p&gt;There are a few things I still want to do:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;re-run the fine-tune on the cleaned dataset&lt;/li&gt;
&lt;li&gt;measure throughput and cost-per-post more rigorously&lt;/li&gt;
&lt;li&gt;profile power usage on the Mac Mini rather than just infer the savings qualitatively&lt;/li&gt;
&lt;li&gt;test whether a cascaded setup works better, for example a smaller model first and a larger model only on borderline posts&lt;/li&gt;
&lt;li&gt;publish more of the evaluation tooling once I have cleaned it up a bit&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I also want to keep pressure-testing the Barbados-specific rules. The line between event, promo, recap, and social chatter is culturally specific, and that is exactly what makes this interesting.&lt;/p&gt;

&lt;p&gt;One of the goals here was never to build a generic event extractor. It was to build something that understands this particular corner of the internet.&lt;/p&gt;

&lt;p&gt;The difference between a proper Barbados party flyer and a post that just happens to have a DJ in it is subtle until you have seen enough of them.&lt;/p&gt;

&lt;p&gt;Then it becomes obvious.&lt;/p&gt;

&lt;p&gt;Well... obvious to a human anyway. Getting a model to internalise that is the fun part.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing
&lt;/h2&gt;

&lt;p&gt;I think local AI is finally at the point where it can do meaningful work for real products, not just demos.&lt;/p&gt;

&lt;p&gt;For me, this is exciting because it opens up a path to making WeOutside246 cheaper to run, more sustainable, and more independent of hosted inference pricing.&lt;/p&gt;

&lt;p&gt;And I quite like the idea that a tiny Mac Mini sat quietly on a desk can now do work that, not very long ago, I would have assumed needed a large remote AI system.&lt;/p&gt;

&lt;p&gt;If you're building something similar, especially anything involving classification plus extraction over messy real-world social media data, I would strongly encourage you to build the evaluation harness first.&lt;/p&gt;

&lt;p&gt;The model leaderboard is interesting. Your own error taxonomy is much more important.&lt;/p&gt;

&lt;p&gt;Anyway, that's where things are up to right now. I'm going to keep iterating on the prompts, probably retrain the 4B fine-tune on the cleaned data, and see how much more I can squeeze out of the local stack.&lt;/p&gt;

&lt;p&gt;Stay tuned. WeOutside246 is getting a lot smarter.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>macmini</category>
      <category>llm</category>
    </item>
    <item>
      <title>Why Semantic Search Matters... especially in Barbados!</title>
      <dc:creator>Matt Hamilton</dc:creator>
      <pubDate>Tue, 02 Dec 2025 21:31:43 +0000</pubDate>
      <link>https://dev.to/hammertoe/why-semantic-search-matters-especially-in-barbados-pc4</link>
      <guid>https://dev.to/hammertoe/why-semantic-search-matters-especially-in-barbados-pc4</guid>
      <description>&lt;h2&gt;
  
  
  How Semantic Search Finds Products That Keywords Miss
&lt;/h2&gt;

&lt;p&gt;I've been building this product search engine for Barbados called "Yuh Gettin' Tru?" (Bajan for "Are you finding what you need?"), and I wanted to share something that perfectly illustrates why semantic search matters.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem with Traditional Search
&lt;/h2&gt;

&lt;p&gt;I was testing the site against a local home store called Dwellings. They sell all sorts of home goods - furniture, kitchenware, decor. I searched for "hardwood cutting board" on their website and got... nothing. Zero results.&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.amazonaws.com%2Fuploads%2Farticles%2Fx3okfj8re3vd329wdy3y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx3okfj8re3vd329wdy3y.png" alt="Screenshot of Dwellings website showing no results for hardwood cutting board" width="800" height="488"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, here's the thing. They absolutely &lt;em&gt;do&lt;/em&gt; sell hardwood cutting boards. They have these lovely acacia wood boards with handles. But their product database doesn't call them "hardwood cutting boards" - it calls them "Acacia Cutting Board with Handle".&lt;/p&gt;

&lt;p&gt;Traditional keyword search sees "hardwood" and "acacia" as completely different strings. No overlap, no match, no results. The customer leaves, probably assumes the store doesn't stock what they need.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Semantic Search Does Differently
&lt;/h2&gt;

&lt;p&gt;When you search for "hardwood cutting board" in Yuh Gettin' Tru?, the system understands that you're looking for a cutting board made from hard, durable wood. It doesn't just match keywords - it matches &lt;em&gt;meaning&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.amazonaws.com%2Fuploads%2Farticles%2Fgrbo6wd7pkk40uew7a12.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgrbo6wd7pkk40uew7a12.png" alt="Screenshot of YuhGettinTru searching for hardwood cutting board and it matching an Acacia cutting board and saying why" width="800" height="774"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The same search returns those acacia cutting boards with a 90% match score. And here's the bit I'm particularly pleased with - it explains &lt;em&gt;why&lt;/em&gt; it matched:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"This is a cutting board made of acacia wood, which is a type of hardwood. It is a very good match for the query."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The system knows that acacia is a hardwood. Not because someone manually tagged it, but because the embedding model (sentence-transformers/all-MiniLM-L6-v2) has learned the semantic relationship between these concepts.&lt;/p&gt;

&lt;h2&gt;
  
  
  How It Works Under the Hood
&lt;/h2&gt;

&lt;p&gt;The technical pipeline is quite satisfying to work on:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Vector embeddings&lt;/strong&gt; - Each product gets converted into a 384-dimensional vector that captures its semantic meaning. "Acacia cutting board" and "hardwood cutting board" end up quite close in this vector space because they mean similar things.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Similarity search&lt;/strong&gt; - MongoDB Atlas Vector Search finds the closest matches in milliseconds, regardless of exact wording.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;LLM reranking&lt;/strong&gt; - Gemini Flash takes the top candidates and scores each one for genuine relevance, filtering out false positives and generating those explanations.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The whole process takes about 3-5 seconds, most of which is the LLM reranking. The vector search itself is lightning fast.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Matters for Caribbean Retail
&lt;/h2&gt;

&lt;p&gt;Barbados has a fragmented retail landscape. Dozens of stores, each sourcing goods from different parts of the world - some from the US, some from the UK, some from Asia. This means product terminology varies wildly.&lt;/p&gt;

&lt;p&gt;Take "cutlery" versus "flatware". If you're British (or Bajan, since we inherited British English), you call your knives and forks "cutlery". But many retailers here source from American suppliers, and their databases use "flatware" instead. Search for "cutlery" on some store websites and you get nothing. The products exist, they're just labelled differently.&lt;/p&gt;

&lt;p&gt;Semantic search understands that cutlery and flatware mean the same thing. It bridges the gap between how customers think about products and how retailers happen to have labelled them.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Small Things
&lt;/h2&gt;

&lt;p&gt;I think what I enjoy most about this project is how the small technical decisions compound into real user value. Choosing the right embedding model. Adding category extraction from breadcrumbs. Structuring the embedding text with labels like "product:" and "brand:" to give the model more context.&lt;/p&gt;

&lt;p&gt;None of these are flashy features. But together, they mean a customer searching for "hardwood cutting board" actually finds the acacia board they're looking for.&lt;/p&gt;

&lt;p&gt;The small things. They matter.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Making Services Discoverable with ERC-8004: Trustless Agent Registration with Filecoin Pin</title>
      <dc:creator>Matt Hamilton</dc:creator>
      <pubDate>Tue, 04 Nov 2025 21:51:57 +0000</pubDate>
      <link>https://dev.to/hammertoe/making-services-discoverable-with-erc-8004-trustless-agent-registration-with-filecoin-pin-1al3</link>
      <guid>https://dev.to/hammertoe/making-services-discoverable-with-erc-8004-trustless-agent-registration-with-filecoin-pin-1al3</guid>
      <description>&lt;p&gt;Making Services Discoverable with ERC-8004: Trustless Agent Registration with Filecoin Pin&lt;/p&gt;

&lt;p&gt;I've been thinking a lot about agent metadata lately. Not the sexy stuff, not the AI models or the clever algorithms. The boring bit. Where do you put the JSON file that describes what an agent does?&lt;/p&gt;

&lt;p&gt;It's one of those problems that seems trivial until you actually try to solve it properly. You can't store it on-chain (too expensive). You can't use regular IPFS pinning (it might disappear). You can't use AWS (defeats the whole point of decentralisation). So what do you do?&lt;/p&gt;

&lt;p&gt;This week, I finally got a chance to properly explore this by registering GitHub's MCP server as an &lt;a href="https://eips.ethereum.org/EIPS/eip-8004" rel="noopener noreferrer"&gt;ERC-8004&lt;/a&gt; agent with &lt;a href="https://docs.filecoin.io/builder-cookbook/filecoin-pin" rel="noopener noreferrer"&gt;Filecoin Pin&lt;/a&gt;. Here's what I learnt.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;The issue is simple enough to explain: when you register an agent, you need to point to some metadata, a JSON file describing what it does, how to connect to it, what it's capable of. The &lt;code&gt;tokenURI&lt;/code&gt; in ERC-8004 parlance.&lt;/p&gt;

&lt;p&gt;You can't store this on-chain. A typical agent card is 1-2KB of JSON. On Ethereum mainnet, that's prohibitively expensive. Even on L2s, you're looking at a chunk of change for every agent registration.&lt;/p&gt;

&lt;p&gt;So you store it off-chain and reference it. Which raises the obvious question: where?&lt;/p&gt;

&lt;p&gt;Generic IPFS pinning services? They can drop your content. No guarantees. Centralised storage like AWS? Single point of failure, ongoing costs, and frankly defeats the point. Store everything on-chain anyway? Not practical.&lt;/p&gt;

&lt;p&gt;I needed something that would actually work long-term.&lt;/p&gt;

&lt;h2&gt;
  
  
  Filecoin Pin
&lt;/h2&gt;

&lt;p&gt;I'd been aware of Filecoin Pin for a while but hadn't actually tried it. The pitch is compelling: you get cryptographic proof that your data is being stored. Daily PDP (Proof of Data Possession) checks. Decentralised across Filecoin's storage network. IPFS compatible so it works with existing tooling.&lt;/p&gt;

&lt;p&gt;The key bit is that last part about proof. With generic IPFS pinning, you're trusting that someone, somewhere, is keeping your content around. With Filecoin Pin, you can actually verify it. Daily proofs that storage providers are holding your data.&lt;/p&gt;

&lt;p&gt;That matters for agent metadata. If you're building something meant to last years, you need more than hope.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Actually Built
&lt;/h2&gt;

&lt;p&gt;For this experiment, I took GitHub's existing MCP server and registered it as an ERC-8004 agent. Not building something new, just making something that already exists discoverable through the registry.&lt;/p&gt;

&lt;p&gt;GitHub already runs a public MCP server at &lt;code&gt;https://api.githubcopilot.com/mcp/&lt;/code&gt;. It provides repository management, issue tracking, PR tools. The usual GitHub stuff exposed through the Model Context Protocol. It's real, it's running, and anyone can use it.&lt;/p&gt;

&lt;p&gt;What it didn't have was an ERC-8004 identity. No way for other agents to discover it. No on-chain registration. No verifiable metadata storage.&lt;/p&gt;

&lt;p&gt;So I created an agent card (a JSON file describing the service), stored it on Filecoin Pin, and registered it on the Identity Registry on Base Sepolia. Now it has a verifiable, discoverable identity.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Agent Card
&lt;/h3&gt;

&lt;p&gt;The agent card is a JSON file that describes the MCP server's capabilities and how to connect to it:&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;"type"&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://eips.ethereum.org/EIPS/eip-8004#registration-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;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GitHub Integration Agent"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AI agent providing GitHub repository, issue, and pull request management capabilities..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"endpoints"&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;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MCP"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"endpoint"&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://api.githubcopilot.com/mcp/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"capabilities"&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;"tools"&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;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"repository_management"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Browse code, search files, analyze commits..."&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;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"issue_management"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Create, update, search, and manage GitHub issues..."&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;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"pull_request_management"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Review PRs, manage approvals, merge conflicts..."&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;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;"supportedTrust"&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;"reputation"&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;This agent card gets uploaded to Filecoin Pin, which returns a CID (Content Identifier). That CID then gets registered on-chain as &lt;code&gt;ipfs://&amp;lt;CID&amp;gt;/github-agent-card.json&lt;/code&gt;, effectively creating a verifiable, discoverable identity for GitHub's existing MCP server.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Complete Workflow
&lt;/h2&gt;

&lt;p&gt;Here's how the pieces fit together:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Upload to Filecoin Pin
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;filecoin-pin add &lt;span class="nt"&gt;--auto-fund&lt;/span&gt; github-agent-card.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This uploads your agent card and returns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Root CID&lt;/strong&gt; - The IPFS identifier&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dataset ID&lt;/strong&gt; - For checking PDP proof status&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Storage deal confirmation&lt;/strong&gt; - Proof it's being stored&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;--auto-fund&lt;/code&gt; flag ensures your storage provider wallet has sufficient USDFC (Filecoin stablecoin) to pay for storage.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Register on Base Sepolia
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cast send 0x7177a6867296406881E20d6647232314736Dd09A &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"register(string)"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"ipfs://&amp;lt;CID&amp;gt;/github-agent-card.json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--rpc-url&lt;/span&gt; https://sepolia.base.org &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--private-key&lt;/span&gt; &lt;span class="nv"&gt;$PRIVATE_KEY&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This mints an ERC-721 NFT representing your agent on the ERC-8004 Identity Registry.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why Base Sepolia?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Low gas costs (it's an L2)&lt;/li&gt;
&lt;li&gt;Official ERC-8004 reference implementation is deployed there&lt;/li&gt;
&lt;li&gt;Easy to get testnet ETH from faucets&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Verify PDP Proofs
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;filecoin-pin data-set &amp;lt;dataset-id&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This shows you the proof status:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Dataset ID: 933
Root CID: bafybeihhal5hlbylkibniig6j72wdrm7lr4nf6z47natleh2jkyosrg7di
Storage Provider: f01234
Status: Active
Last PDP Proof: 2025-01-15 14:32:10 UTC
Next Proof: 2025-01-16 14:32:10 UTC
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Daily proofs&lt;/strong&gt; mean you can always verify your agent metadata is still being stored. This is the cryptographic guarantee that sets Filecoin Pin apart.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Agent Discovery
&lt;/h3&gt;

&lt;p&gt;Now any application can discover and use your agent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Query the registry&lt;/span&gt;
cast call 0x7177a6867296406881E20d6647232314736Dd09A &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"tokenURI(uint256)"&lt;/span&gt; 55 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--rpc-url&lt;/span&gt; https://sepolia.base.org

&lt;span class="c"&gt;# Returns: ipfs://bafybeihhal5hlbylkibniig6j72wdrm7lr4nf6z47natleh2jkyosrg7di/github-agent-card.json&lt;/span&gt;

&lt;span class="c"&gt;# Fetch the agent card&lt;/span&gt;
curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="s2"&gt;"https://ipfs.io/ipfs/bafybeihhal5hlbylkibniig6j72wdrm7lr4nf6z47natleh2jkyosrg7di/github-agent-card.json"&lt;/span&gt; | jq &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent card tells them how to connect to the GitHub MCP server and what capabilities are available.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Matters for Builders
&lt;/h2&gt;

&lt;p&gt;This is still very much a work in progress. Everything here is running on testnets, and we're actively figuring out what the production infrastructure should look like. But having said that, the pattern is already useful for making any existing service discoverable as an ERC-8004 agent with verifiable, persistent metadata.&lt;/p&gt;

&lt;h3&gt;
  
  
  For Agent Builders
&lt;/h3&gt;

&lt;p&gt;You get:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Peace of mind&lt;/strong&gt; - Your agent metadata won't disappear&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verifiability&lt;/strong&gt; - Anyone can check that storage is active&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Decentralisation&lt;/strong&gt; - No single point of failure&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Standards compliance&lt;/strong&gt; - Works with ERC-8004 ecosystem&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  For Agent Users
&lt;/h3&gt;

&lt;p&gt;They get:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Trust&lt;/strong&gt; - Can verify agents are legitimate and persistent&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Discovery&lt;/strong&gt; - Find agents via on-chain registry&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Composability&lt;/strong&gt; - Combine multiple agents together&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transparency&lt;/strong&gt; - See full agent capabilities before using&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  For the Ecosystem
&lt;/h3&gt;

&lt;p&gt;We get:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Infrastructure&lt;/strong&gt; for the emerging agent economy&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Interoperability&lt;/strong&gt; via ERC-8004 standard&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Long-term viability&lt;/strong&gt; with provable storage&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Foundation&lt;/strong&gt; for reputation and validation systems&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Whilst these lists look a bit like marketing bullet points, each of these actually matters. The infrastructure piece is what I find most interesting, because we're finally building the plumbing that makes agent composition practical.&lt;/p&gt;

&lt;p&gt;We'd love to have more developers try this out and give us feedback on what works and what doesn't.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try It Yourself
&lt;/h2&gt;

&lt;p&gt;So if you want to give this a go, I've put together a complete tutorial that walks you through every step:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="//./TUTORIAL.md"&gt;Register an ERC-8004 Agent with Filecoin Pin Storage&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The tutorial includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Complete prerequisites and token setup&lt;/li&gt;
&lt;li&gt;Step-by-step commands with expected outputs&lt;/li&gt;
&lt;li&gt;Screenshot indicators showing what you should see&lt;/li&gt;
&lt;li&gt;Troubleshooting for common issues&lt;/li&gt;
&lt;li&gt;Example agent card you can customise&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everything you need is in the tutorial. It's designed to take you from zero to a registered agent in about 30-45 minutes. Having said that, if it's your first time working with Filecoin or Base Sepolia, you might want to give yourself a bit more time to get familiar with the faucets and tooling.&lt;/p&gt;

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

&lt;p&gt;Well, this is just the beginning. The ERC-8004 standard includes three registries:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Identity Registry&lt;/strong&gt; (what I demonstrated here) - Register and discover agents&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reputation Registry&lt;/strong&gt; (coming) - Build trust through verified actions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validation Registry&lt;/strong&gt; (coming) - Third-party verification of agent behaviour&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Combining these with provable storage creates the foundation for a real agent economy. I think the reputation piece is going to be particularly interesting, because that's where agents can start to build track records that others can actually verify.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ideas to Explore
&lt;/h3&gt;

&lt;p&gt;Some things I'm thinking about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Multi-agent systems&lt;/strong&gt; - Agents that discover and compose with other agents&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reputation building&lt;/strong&gt; - Agents that accumulate verified track records&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validator networks&lt;/strong&gt; - Decentralised verification of agent behaviour&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Agent marketplaces&lt;/strong&gt; - Discover and use agents based on capabilities and reputation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-chain agents&lt;/strong&gt; - Agents that operate across multiple networks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There's probably a lot more that I haven't thought of yet. If any of this sounds like something you're working on, I'd love to hear about it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Bigger Picture
&lt;/h2&gt;

&lt;p&gt;I think we're at an inflection point. AI agents are becoming capable enough to act autonomously, but they need decentralised infrastructure to be truly trustless.&lt;/p&gt;

&lt;p&gt;By solving the storage problem with Filecoin Pin and the identity problem with ERC-8004, we're enabling a new category of applications:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Autonomous trading agents&lt;/strong&gt; with verifiable track records&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code review agents&lt;/strong&gt; that build reputation over time&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data analysis agents&lt;/strong&gt; that can be audited and verified&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Coordination agents&lt;/strong&gt; that compose multiple specialised agents&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Personal assistants&lt;/strong&gt; that users actually own and control&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The key insight? &lt;strong&gt;Agents aren't just smart contracts. They're long-lived entities that need persistent, verifiable infrastructure.&lt;/strong&gt; It has been a challenge working out what that infrastructure looks like, but I think the combination of ERC-8004 and Filecoin Pin gets us pretty close.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Involved
&lt;/h2&gt;

&lt;p&gt;The ERC-8004 ecosystem is just getting started, and we need builders to shape it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you want to try this out:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Follow the &lt;a href="//./TUTORIAL.md"&gt;tutorial&lt;/a&gt; to register your first agent&lt;/li&gt;
&lt;li&gt;Join the &lt;a href="https://github.com/ethereum/EIPs/issues/8004" rel="noopener noreferrer"&gt;ERC-8004 discussions&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Check out the &lt;a href="https://github.com/ChaosChain/trustless-agents-erc-ri" rel="noopener noreferrer"&gt;reference implementation&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Explore &lt;a href="https://docs.filecoin.io/builder-cookbook/filecoin-pin" rel="noopener noreferrer"&gt;Filecoin Pin documentation&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Some things you could build:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Register your existing services as ERC-8004 agents&lt;/li&gt;
&lt;li&gt;Build agent discovery tools&lt;/li&gt;
&lt;li&gt;Develop reputation systems&lt;/li&gt;
&lt;li&gt;Create validator networks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The infrastructure is ready. The standard is here. So if any of this sounds like it would be useful for what you're building, then get in touch and let's chat!&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tutorial&lt;/strong&gt;: &lt;a href="https://docs.filecoin.io/builder-cookbook/filecoin-pin/" rel="noopener noreferrer"&gt;Register an ERC-8004 Agent with Filecoin Pin&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ERC-8004 Specification&lt;/strong&gt;: &lt;a href="https://eips.ethereum.org/EIPS/eip-8004" rel="noopener noreferrer"&gt;https://eips.ethereum.org/EIPS/eip-8004&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Filecoin Pin CLI&lt;/strong&gt;: &lt;a href="https://docs.filecoin.io/builder-cookbook/filecoin-pin/filecoin-pin-cli" rel="noopener noreferrer"&gt;https://docs.filecoin.io/builder-cookbook/filecoin-pin/filecoin-pin-cli&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Base Sepolia Faucet&lt;/strong&gt;: &lt;a href="https://www.alchemy.com/faucets/base-sepolia" rel="noopener noreferrer"&gt;https://www.alchemy.com/faucets/base-sepolia&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Example Agent&lt;/strong&gt;: &lt;a href="https://sepolia.basescan.org/token/0x7177a6867296406881E20d6647232314736Dd09A?a=55" rel="noopener noreferrer"&gt;View on Basescan&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>agents</category>
      <category>ethereum</category>
      <category>architecture</category>
      <category>web3</category>
    </item>
    <item>
      <title>Building "Yuh Hear Dem": A Parliamentary AI with Google's ADK and a Lesson in Agentic Design</title>
      <dc:creator>Matt Hamilton</dc:creator>
      <pubDate>Thu, 19 Jun 2025 01:01:54 +0000</pubDate>
      <link>https://dev.to/hammertoe/building-yuh-hear-dem-a-parliamentary-ai-with-googles-adk-and-a-lesson-in-agentic-design-247</link>
      <guid>https://dev.to/hammertoe/building-yuh-hear-dem-a-parliamentary-ai-with-googles-adk-and-a-lesson-in-agentic-design-247</guid>
      <description>&lt;p&gt;Democracy thrives on transparency, but the raw data of governance—hours of parliamentary video, dense transcripts, and complex legislation—is often inaccessible to the very citizens it’s meant to serve. This was the challenge that sparked "Yuh Hear Dem," our submission for the &lt;strong&gt;&lt;a href="https://devpost.com/software/yuh-hear-dem-adk" rel="noopener noreferrer"&gt;Google Agent Development Kit (ADK) Hackathon&lt;/a&gt;&lt;/strong&gt;. The project began as a father-daughter mentoring journey into AI and evolved into a powerful tool for civic engagement in Barbados. It combines deep experience in backend AI architecture with a fresh perspective on user experience, guided by principles from the world of education. This blend allowed us to build a system that is not only technically sophisticated but also genuinely accessible, transforming the way citizens can interact with their government.&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.amazonaws.com%2Fuploads%2Farticles%2Fbqs9pqdezlm00ut4l5pd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbqs9pqdezlm00ut4l5pd.png" alt="Asking a question" width="800" height="876"&gt;&lt;/a&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.amazonaws.com%2Fuploads%2Farticles%2Fqrfibpgb15q7tekfwvr8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqrfibpgb15q7tekfwvr8.png" alt="Visualising the knowledge graph" width="800" height="941"&gt;&lt;/a&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.amazonaws.com%2Fuploads%2Farticles%2Fmv975q7fo1837xubzu6f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmv975q7fo1837xubzu6f.png" alt="Youtube video provenance" width="800" height="876"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This post details our technical journey, from the initial data pipeline to a crucial architectural pivot, all powered by Google's Agent Development Kit (ADK), Gemini, and a Knowledge Graph backend.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Problem: From Hours of Video to Actionable Insight
&lt;/h3&gt;

&lt;p&gt;Parliamentary sessions in Barbados, like in many places, are published as long-form YouTube videos. Finding what a specific minister said about a particular topic, like the "sugar tax," requires manually scrubbing through hours of footage. This creates a significant barrier to civic engagement.&lt;/p&gt;

&lt;p&gt;Our goal was to transform this unstructured data into a structured, queryable format, allowing any citizen to ask a natural language question and get a direct, source-verified answer.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Solution: An AI-Powered Parliamentary Research Assistant
&lt;/h3&gt;

&lt;p&gt;"Yuh Hear Dem" (Bajan dialect for "Did you hear them?") is a conversational agent that allows users to query parliamentary data. A user can ask, &lt;em&gt;"What has been discussed about the sugar tax?"&lt;/em&gt; and receive a concise summary, direct quotes from MPs, and links to the exact moments in the source videos.&lt;/p&gt;

&lt;p&gt;The system is built on a sophisticated Retrieval-Augmented Generation (RAG) pipeline that combines the semantic power of vector search with the structured precision of a knowledge graph.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Technical Architecture: A Three-Stage Pipeline
&lt;/h3&gt;

&lt;p&gt;Our system is built on a robust data processing and retrieval pipeline.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Ingest, Clean, Extract&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The foundation of our system is a structured knowledge base built from raw, messy transcripts.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Ingest:&lt;/strong&gt; We start by ingesting the full YouTube transcripts from hundreds of parliamentary session videos—over 1,200 hours of content.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Clean:&lt;/strong&gt; The raw transcripts are often riddled with grammatical errors and misattributions. We use &lt;strong&gt;Gemini&lt;/strong&gt; to clean and structure this text, correcting grammar, identifying speakers, and aligning the text with accurate video timestamps.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Extract:&lt;/strong&gt; With clean, timestamped text, we use Gemini again to perform entity and relationship extraction. It identifies people, topics, bills, and the connections between them (e.g., "Minister X &lt;em&gt;spoke about&lt;/em&gt; Bill Y"). This structured data, including over 33,000 nodes and 86,000 statements, is stored in &lt;strong&gt;MongoDB Atlas&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This process creates a rich, interconnected Knowledge Graph that forms the backbone of our agent's "brain."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Hybrid Retrieval with GraphRAG&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When a user asks a question, the agent doesn't just rely on a simple semantic search. It uses a hybrid retrieval strategy:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Vector Search:&lt;/strong&gt; We run a vector search over MongoDB Atlas embeddings to find semantically similar transcript segments. This is great for broad, topic-based queries.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Knowledge Graph Search:&lt;/strong&gt; We traverse the entities and relationships in our knowledge graph to find precise connections (e.g., &lt;code&gt;Minister -&amp;gt; Topic -&amp;gt; Session&lt;/code&gt;). This excels at specific, factual queries.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The results are combined and ranked using a hybrid scoring model (GraphRAG), giving us the best of both worlds. Critically, every piece of information is grounded in video timestamps, allowing us to generate direct links to the source.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. The Agent Architecture Evolution: A Lesson in Pragmatism&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Our journey with ADK taught us a valuable lesson about the current state of multi-agent frameworks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Original Vision: A Multi-Agent Pipeline&lt;/strong&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="c1"&gt;# Root Conversational Agent
&lt;/span&gt;&lt;span class="nc"&gt;ConversationalAgent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gemini-2.0-flash&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;sub_agents&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ResearchPipeline&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Sequential Research Pipeline
&lt;/span&gt;&lt;span class="nc"&gt;ResearchPipeline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SequentialAgent&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="nc"&gt;ResearcherAgent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LlmAgent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;Tools&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;hybrid_search_turtle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;authority_search_turtle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;topic_search_turtle&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;Role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Parliamentary&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="n"&gt;collection&lt;/span&gt; &lt;span class="n"&gt;via&lt;/span&gt; &lt;span class="n"&gt;MCP&lt;/span&gt; &lt;span class="n"&gt;tools&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;
&lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="nc"&gt;ProvenanceAgent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseAgent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;Custom&lt;/span&gt; &lt;span class="n"&gt;Implementation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Video&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt; &lt;span class="n"&gt;enrichment&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;Role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Enrich&lt;/span&gt; &lt;span class="n"&gt;entities&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;YouTube&lt;/span&gt; &lt;span class="n"&gt;timestamps&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;transcripts&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;
&lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="nc"&gt;WriterAgent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LlmAgent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;Dynamic&lt;/span&gt; &lt;span class="n"&gt;Instruction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Receives&lt;/span&gt; &lt;span class="n"&gt;enriched&lt;/span&gt; &lt;span class="n"&gt;turtle&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;
    &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;Role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Synthesize&lt;/span&gt; &lt;span class="n"&gt;findings&lt;/span&gt; &lt;span class="n"&gt;into&lt;/span&gt; &lt;span class="n"&gt;cited&lt;/span&gt; &lt;span class="n"&gt;responses&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Initially, we designed a classic multi-agent system using a &lt;code&gt;SequentialAgent&lt;/code&gt;. The idea was to have a clear separation of concerns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;ConversationalAgent:&lt;/strong&gt; The main entry point.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;ResearchPipeline (&lt;code&gt;SequentialAgent&lt;/code&gt;):&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;ResearcherAgent:&lt;/strong&gt; Collects data from our knowledge graph.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;ProvenanceAgent:&lt;/strong&gt; Enriches the data with video sources and timestamps.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;WriterAgent:&lt;/strong&gt; Synthesizes the final response.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The Roadblock: Session State Management&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We quickly hit a wall. We found that &lt;code&gt;ctx.session.state&lt;/code&gt; was not being reliably shared between the agents in our &lt;code&gt;SequentialAgent&lt;/code&gt; pipeline. The &lt;code&gt;ResearcherAgent&lt;/code&gt; would fetch data, but by the time the flow reached the &lt;code&gt;ProvenanceAgent&lt;/code&gt; or &lt;code&gt;WriterAgent&lt;/code&gt;, the state was often empty or corrupted.&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="c1"&gt;# What SHOULD have worked:
&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;turtle_results&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;raw_turtle_data&lt;/span&gt;  &lt;span class="c1"&gt;# ResearcherAgent
&lt;/span&gt;&lt;span class="n"&gt;enriched_turtle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;turtle_results&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="c1"&gt;# ProvenanceAgent ❌
&lt;/span&gt;
&lt;span class="c1"&gt;# What we encountered:
# - Session state not reliably shared between agents in SequentialAgent
# - Context loss during agent handoffs  
# - Empty/corrupted state in downstream agents
# - Related to: https://github.com/google/adk-python/issues/1119
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This appears to be a known challenge, which we tracked in &lt;a href="https://github.com/google/adk-python/issues/1119" rel="noopener noreferrer"&gt;GitHub Issue #1119&lt;/a&gt;. This roadblock became a critical learning moment: while the theory of multi-agent systems is powerful, the practical implementation can be fraught with state management complexities.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Pivot: A Robust Single-Agent Solution&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To solve this, we refactored our architecture into a &lt;strong&gt;single intelligent agent with a set of specialized function tools&lt;/strong&gt;. This approach proved to be far more reliable and easier to debug.&lt;/p&gt;

&lt;p&gt;The agent maintains context reliably, and the tools are called synchronously, ensuring data is passed correctly.&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="c1"&gt;# Refactored Single-Agent Solution
&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;agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LlmAgent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;YuhHearDem&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gemini-2.5-flash-preview-05-20&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;planner&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;BuiltInPlanner&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="nc"&gt;FunctionTool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;search_parliament_hybrid&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;# Was: ResearcherAgent
&lt;/span&gt;        &lt;span class="nc"&gt;FunctionTool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clear_session_graph&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;      &lt;span class="c1"&gt;# Memory management
&lt;/span&gt;        &lt;span class="nc"&gt;FunctionTool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get_session_graph_stats&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;  &lt;span class="c1"&gt;# Session insights
&lt;/span&gt;        &lt;span class="nc"&gt;FunctionTool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;visualize_knowledge_graph&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# Was: Custom visualization
&lt;/span&gt;    &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This pragmatic pivot allowed us to achieve our desired modularity—with each tool handling a specific task—without the overhead and unreliability of inter-agent state management.&lt;/p&gt;

&lt;h3&gt;
  
  
  The User Experience: Making AI Accessible
&lt;/h3&gt;

&lt;p&gt;Technology is only as good as its interface. Our focus on educational design was instrumental here. The frontend was built to make the agent's powerful capabilities accessible to everyone.&lt;/p&gt;

&lt;p&gt;Key design principles included:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Progressive Disclosure:&lt;/strong&gt; Information is presented in expandable cards, preventing cognitive overload. Users see a high-level summary first and can expand for details.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Visual Learning:&lt;/strong&gt; We used D3.js to create interactive knowledge graphs, helping users visually understand the relationships between speakers, topics, and sessions.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Contextual Guidance:&lt;/strong&gt; The agent uses the knowledge graph to generate relevant follow-up questions, guiding users on natural exploration paths.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Conclusion and What's Next
&lt;/h3&gt;

&lt;p&gt;"Yuh Hear Dem" is more than just a technical demo; it's a functioning tool for enhancing democratic transparency. Our journey taught us several key lessons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;The Power of Hybrid RAG:&lt;/strong&gt; Combining knowledge graphs and vector search provides superior retrieval accuracy.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;ADK's Strengths:&lt;/strong&gt; While multi-agent state sharing needs maturing, ADK’s single-agent with function tools model is incredibly robust for building complex, reliable AI systems.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Pragmatism Over Purity:&lt;/strong&gt; A simpler, more reliable architecture is often better than a theoretically "purer" but fragile one.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Human-Centered Design is Key:&lt;/strong&gt; An intuitive UI, grounded in learning principles, is essential for making powerful AI accessible and useful.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We invite you to explore the project yourself.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Live Site:&lt;/strong&gt; &lt;a href="https://yuhheardem.com" rel="noopener noreferrer"&gt;https://yuhheardem.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Git Repo:&lt;/strong&gt; &lt;a href="https://github.com/KatieM00/YuhHearDem" rel="noopener noreferrer"&gt;https://github.com/KatieM00/YuhHearDem&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Hackathon Submission:&lt;/strong&gt; &lt;a href="https://devpost.com/software/yuh-hear-dem-adk" rel="noopener noreferrer"&gt;https://devpost.com/software/yuh-hear-dem-adk&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Our next steps involve expanding the data sources to include official legislative documents and exploring a return to a multi-agent architecture as the ADK framework evolves. For now, we're proud to have built a tool that helps citizens hear what really matters.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>hackathon</category>
      <category>gemini</category>
      <category>python</category>
    </item>
    <item>
      <title>Lift as You Climb</title>
      <dc:creator>Matt Hamilton</dc:creator>
      <pubDate>Tue, 26 Jul 2022 17:34:14 +0000</pubDate>
      <link>https://dev.to/hammertoe/lift-as-you-climb-33in</link>
      <guid>https://dev.to/hammertoe/lift-as-you-climb-33in</guid>
      <description>&lt;p&gt;It was Sunday the 7th of June 2020. The first wave of the Covid-19 pandemic had hit and everywhere was in strict lockdown. I can't remember the exact specifics, but I think I was probably sat on the couch in my house in the UK at the time, perusing Twitter on my phone. I stumbled across a tweet from a Developer Advocate at Microsoft, Brandon. I'm not sure I was even following him at the time, but it was probably retweeted by someone I was following.&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1269740874721710080-612" src="https://platform.twitter.com/embed/Tweet.html?id=1269740874721710080"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1269740874721710080-612');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1269740874721710080&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;I went upstairs to my “home office” that I had set up in the spare bedroom. I had started a new role as a Developer Advocate at IBM a few months prior. I'd only visited the office in London once, just before the lockdowns came into effect. As a team whose main role was in-person meetups and events in the UK, we were trying to re-orient ourselves to producing online content. As a part of that, I had recently started Twitch streaming myself. I'd not used Twitch before, but become aware of it via some other colleagues at IBM that were using it for live-coding and education. I loved the idea (and it terrified me!) that you could just broadcast yourself coding and other people might drop in the chat to keep you company, offer assistance, chat nonsense, etc.&lt;/p&gt;

&lt;p&gt;Anyway, I joined PJ's channel and he was there learning the very basics of, I think, HTML at the time. Maybe C#. Brandon was there too assisting him. I think there was no more than 3-4 people in the chat. But it felt great to be able to help someone start learning the basics. Every so often PJ would divert into something about literature (he was an English teacher after all) and talk about some paragraph of a book, or some poet I'd never heard of. But it was enjoyable. Listening to his passion about literature, and trying to channel that into learning something new.&lt;/p&gt;

&lt;p&gt;I started following &lt;a href="https://twitter.com/MetzinAround" rel="noopener noreferrer"&gt;PJ on Twitter&lt;/a&gt;, as well as &lt;a href="https://twitter.com/TheCodeTraveler" rel="noopener noreferrer"&gt;Brandon&lt;/a&gt; and another Developer Advocate friend of theirs &lt;a href="https://twitter.com/ChloeCondon" rel="noopener noreferrer"&gt;Chloe&lt;/a&gt;. Together they created a bunch of silly little bots on Twitter, e.g. the Shania bot ("Let's go girls!"). A bot that begged Mountain Dew for sponsorship (at least I &lt;em&gt;think&lt;/em&gt; that one was a bot). Chloe was also from a non-programming background, having originally come from theatre arts and stage school into DevRel. They did some fantastically entertaining shows online and started a &lt;a href="https://podcasts.apple.com/us/podcast/8-bits/id1541214537" rel="noopener noreferrer"&gt;Podcast called 8-bits&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;PJ eventually managed to get a role in DevRel and is now an Education evangelist at Gitlab.&lt;/p&gt;

&lt;p&gt;This is all great Matt, but so what?&lt;/p&gt;

&lt;p&gt;It is just over two years since that tweet at the top, and stumbling across PJ and his journey into DevRel, and Chloe and her journey from theatre arts to DevRel.&lt;/p&gt;

&lt;p&gt;A few days ago I was interviewing for a company for a senior developer relations role. I had four different interviews, covering different aspects such as my technical knowledge or my thoughts on developer advocacy, building and leading teams, etc.&lt;/p&gt;

&lt;p&gt;One specific question I was asked in the last interview was:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Do you think a developer advocate needs to have a software development / technical background?".&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And some neurons somewhere in the recesses of my brain fired and I remembered PJ, and Chloe and their origins in high school english teaching and stage acting.&lt;/p&gt;

&lt;p&gt;"No." I replied. And I went on to explain that the most important aspect, in my view, for developer relations is the ability to relate to and empathise with developers. Yes, of course, one of the most obvious ways is to have a development or technical background yourself. But actually, those coming into tech from other backgrounds are learning themselves. They have very fresh experience of having to learn the new terminology, functionality, etc of a product and explain it to others. They bring different skills, and different experiences to the table. &lt;/p&gt;

&lt;p&gt;I remember myself when I first started learning AI and machine learning. Whilst I was a developer, I had no experience yet in machine learning. "Is that a regression problem or a classification problem?". I had no idea. I didn't even understand the terminology to describe what I was trying to learn. What is a tensor? What is a logit? So when I moved into doing DevRel for machine learning, I was able to think "What would I like to have known when I started in machine learning that would have made it easier for me?".&lt;/p&gt;

&lt;p&gt;Another question I was asked in the interview:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Can you give an example of where you have helped another developer progress?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Again, I remembered another event that came from a random encounter. We were running an internal hackathon at Ripple, and a developer, Ami, from a different part of the company, that I'd never come across presented a fantastic hackathon project they were working on. I had recently been accepted as a speaker at Python Web Conference 2022, and the topic I was going to speak on aligned very much with what Ami developed in the hackathon. I approached Ami after the hackathon, and asked if she would like to co-present a talk with me at the conference. She was a fantastic developer, but I could see she would make a really good developer advocate as well. She had never spoken at a conference before, but agreed to do so. I contacted the conference organisers and let them know I'd now be co-presenting with a colleague. &lt;/p&gt;

&lt;p&gt;The talk went fantastically! I talked about the general topic, and Ami gave a live-coding demo. A pretty amazing feat for someone's first conference talk!&lt;/p&gt;

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

&lt;p&gt;Around that time I left Ripple, but Ami wanted to stay in touch and asked me to be her mentor. I was honoured, and glad to be able to help in any way I could. I hope one day she makes the move full-time into DevRel!&lt;/p&gt;

&lt;p&gt;So this brings me back to the title of this post, "Lift as you climb". This was a saying I &lt;a href="https://medium.com/ux-and-front-end-interviews/lift-as-you-climb-an-interview-with-cassidy-williams-d76a742d3aea" rel="noopener noreferrer"&gt;first heard from another developer advocate, Cassidy Williams&lt;/a&gt;. As you learn and progress, help bring others along with you too. In that post she talks about the importance of communities and mentorship:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“I wouldn’t be where I am today if it wasn’t for the community around me,” Cassidy points out. “You can do pretty well on your own in tech but you can really succeed if you have a community that you help that then helps you in return.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And so I'd like to take this time to thank all those random people I've interacted with over the years that have got me to where I am now. Many of you may not have even realised how you have helped.&lt;/p&gt;

&lt;p&gt;Oh... and I got the job! ;)&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Header Photo by &lt;a href="https://unsplash.com/@alpifree?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Sylvain Mauroux&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/climbing?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>devrel</category>
      <category>learning</category>
      <category>programming</category>
      <category>beginners</category>
    </item>
    <item>
      <title>XRPL Grants Wave 3 Theme: Contributing to Open Source</title>
      <dc:creator>Matt Hamilton</dc:creator>
      <pubDate>Fri, 04 Mar 2022 15:34:47 +0000</pubDate>
      <link>https://dev.to/ripplexdev/xrpl-grants-wave-3-theme-contributing-to-open-source-28ob</link>
      <guid>https://dev.to/ripplexdev/xrpl-grants-wave-3-theme-contributing-to-open-source-28ob</guid>
      <description>&lt;h2&gt;
  
  
  Applications for Wave 3 are now open!
&lt;/h2&gt;

&lt;p&gt;The official theme for this wave is “&lt;strong&gt;Contributing to Open Source.&lt;/strong&gt;” The Program aims to support the independent, open-source ecosystem development around the XRP Ledger (XRPL). Making “Contributing to Open Source” the focus area of Wave 3 encourages projects that not only expand and enhance the resources available for XRPL developers, but that also continue to grow and strengthen the XRPL community. Types of projects may include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creating and open-sourcing a new project&lt;/li&gt;
&lt;li&gt;Contributing to an existing open-source project&lt;/li&gt;
&lt;li&gt;Adding XRP or XRP Ledger support to a project&lt;/li&gt;
&lt;li&gt;Integrating the XRP Ledger with existing APIs, SDKs, and technologies that simplify deployment and integration&lt;/li&gt;
&lt;li&gt;Building libraries for the XRP Ledger&lt;/li&gt;
&lt;li&gt;Opening PRs for other projects to support the XRP Ledger&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Projects applications for Wave 3 will be accepted form  March 4 - 28, 2022, and applicants can view and submit their applications online. For all information about applying visit &lt;a href="http://www.xrplgrants.org" rel="noopener noreferrer"&gt;www.xrplgrants.org&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wave 3 Timeline
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Applications Open: March 4 - 28, 2022&lt;/li&gt;
&lt;li&gt;Finalist Interviews: May/June 2022&lt;/li&gt;
&lt;li&gt;Grantees Announced: July 2022&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All applications for Wave 3 will be carefully reviewed by &lt;a href="https://dev.to/ripplexdev/xrpl-grants-expands-judging-committee-140n"&gt;an expert panel of judges&lt;/a&gt; from respected institutions and companies from around the world. Select project teams will then be invited to participate and present in a 30-minute interview with members of the grants team and the judging committee. &lt;/p&gt;

&lt;p&gt;Since the XRPL Grants program launched in May 2021, more than 50 projects have been funded internationally. &lt;a href="https://xrplgrants.org/grantees" rel="noopener noreferrer"&gt;View all the awarded projects&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Join a Live Q&amp;amp;A
&lt;/h2&gt;

&lt;p&gt;We invite anyone interested in learning more about applying for an XRPL Grant to attend our official Q&amp;amp;A on the &lt;a href="https://twitch.tv/ripplexdev" rel="noopener noreferrer"&gt;RippleXDev Twitch channel&lt;/a&gt; on &lt;strong&gt;Tuesday, March 15, 2022 at 11 AM PT (18:00 UTC)&lt;/strong&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  Have more questions about applying?
&lt;/h2&gt;

&lt;p&gt;Answers to commonly asked questions are available on the &lt;a href="https://xrplgrants.org/faq" rel="noopener noreferrer"&gt;FAQ page&lt;/a&gt;. The &lt;a href="http://xrpldevs.org/" rel="noopener noreferrer"&gt;XRPL Developers Discord&lt;/a&gt; is also a great place to connect with the community, including past funding recipients. &lt;/p&gt;

</description>
      <category>xrpl</category>
      <category>xrplgrants</category>
      <category>blockchain</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Debunking the Myths — What Is XRPL</title>
      <dc:creator>Matt Hamilton</dc:creator>
      <pubDate>Thu, 16 Sep 2021 17:09:35 +0000</pubDate>
      <link>https://dev.to/ripplexdev/debunking-the-myths-what-is-xrpl-1m0c</link>
      <guid>https://dev.to/ripplexdev/debunking-the-myths-what-is-xrpl-1m0c</guid>
      <description>&lt;h2&gt;
  
  
  Facts &amp;amp; Fiction: Debunking XRP Ledger Misconceptions
&lt;/h2&gt;

&lt;p&gt;As someone who’s been deeply ingrained in the software development community for 20 years, I’ve come to realize that misinformation propels hearsay unlike anything else. There are a number of falsehoods circling the XRP Ledger (XRPL) that I encounter on a regular basis including the misconception that it’s centralized, that there are hidden fees, that it’s private and used only by banks — and it's time to set the record straight. If you’re a developer interested in building on the XRP Ledger, or you simply want to learn more about the network, keep reading. I’m breaking down the facts and debunking the biggest misconceptions about XRPL.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MYTH: The XRP Ledger is Centralized&lt;/strong&gt;. Based on my experience as a developer and my conversations with fellow devs, this is perhaps the most rampant falsehood — and here’s why. In a centralized blockchain, a single authority governs the entire network, controls validation, controls updates to the ledger, and creates a single point of failure (which theoretically leaves the entire network vulnerable to an attack). &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TRUTH: The XRP Ledger is Decentralized&lt;/strong&gt;. The XRPL delivers powerful utility to developers on a public, decentralized blockchain. Validation occurs via a consensus process where independent nodes are managed by a wide range of participants — not by a singular controlling entity. Amendments to the XRPL can be proposed by any participant and require 80% quorum approval for two consecutive weeks by the validator community. And once confirmed, transactions cannot be reversed or altered.&lt;/p&gt;

&lt;p&gt;These are all hallmarks of decentralized ledgers. If there’s one takeaway I want you to remember, it’s this: Ripple is a contributor to the network, but only one contributor among many. As of writing, Ripple run around 5% of the approximately 900 nodes on the XRP Ledger, and six of the approximately 150 validator nodes. Ripple follows the same protocols and its rights are the same as those of any other contributor. &lt;/p&gt;

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

&lt;h2&gt;
  
  
  Final Myths to Debunk
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;MYTH:  New XRP Can Be Added to the Ledger&lt;/strong&gt;. According to this myth, a single authority can make unilateral changes to the fundamental, underlying code, which leaves the Ledger open to hackers who could create new XRP.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TRUTH&lt;/strong&gt;: Even if a bad actor attempted to add unauthorized XRP to the Ledger, the consensus protocol ensures no single authority can execute on this. More than 66 million ledgers have been successfully closed since the XRP Ledger was first conceived with 100 billion XRP created at the inception of the Ledger, and no additional XRP has ever been added into the system. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MYTH: XRPL Has Hidden Fees&lt;/strong&gt;. Fees, including transaction costs and reserve fees are returned to Ripple after being implemented into the Ledger, or rewarded to validators after being implemented into the XRP Ledger. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TRUTH&lt;/strong&gt;: Just like other public blockchains, transaction fees are applied on the XRP Ledger, although they are far lower than most (just fractions of a cent on XRPL). Unlike other blockchains, however, the fee is neither returned to a central authority or paid as a reward to validators or any other party. It is, in fact, irreversibly destroyed. Because fees rise in-step with the load on the network, this protects the network from spam, malicious behavior and DDoS attacks. Furthermore, XRP transactions on the Ledger are settled almost instantaneously (only 3-5 seconds to confirm completion vs. 10+ minutes for other blockchains, or multiple days for banks to send cross-border fiat funds to other banks). The XRPL consensus protocol bridges the gap, saving substantial time and transaction costs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MYTH: Blockchains Can’t Be Decentralized, Scalable and Secure&lt;/strong&gt;. Improvement in one of these aspects must negatively impact one of the other two. We must sacrifice one to optimize the others, right? Not so fast–here’s the truth. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TRUTH&lt;/strong&gt;: The Blockchain Trilemma is a model to conceptualize the challenges that all blockchains face, stating that the platforms cannot be truly decentralized, scalable and secure all at once. The truth is, the XRP Ledger was the first and is one of only a few blockchains able to run a decentralized, on-chain, limit order book exchange in near real-time. It can sustain a maximum throughput of up to 1,500 transactions per second (scalable), is managed by a range of diverse participants who collectively confirm transactions and approve proposed amendments (decentralized) and utilizes consensus protocol that protects against attacks and failure modes (security). And XRPL does all this in a very sustainable way. In fact it is the world’s first major, global, carbon-neutral blockchain.&lt;/p&gt;

&lt;h2&gt;
  
  
  In Conclusion…
&lt;/h2&gt;

&lt;p&gt;Developers need to find the best blockchain for their project requirements. Any misunderstanding around how the tech works hinders that process. &lt;/p&gt;

&lt;p&gt;By diving into the nuts and bolts of how the XRPL operates, we’ve been able to debunk several myths and misconceptions about the ledger as well as review some of the advantages that make it ideal for a wide variety of projects. Hopefully, this overview will help you to look beyond the unfounded myths circulating about the XRPL to discover another viable tool for your needs.&lt;/p&gt;

&lt;p&gt;For more information, head to &lt;a href="https://xrpl.org" rel="noopener noreferrer"&gt;XRPL.org&lt;/a&gt;, where you can find plenty of background information, documentation, updates on ongoing projects and an extensive FAQ. &lt;/p&gt;

&lt;p&gt;Any other misconceptions you’ve seen that I didn’t address? Let us know in the comments right here. &lt;/p&gt;

</description>
      <category>xrp</category>
      <category>xrpl</category>
      <category>blockchain</category>
      <category>myths</category>
    </item>
    <item>
      <title>A Vision for Federated Sidechains on the XRP Ledger</title>
      <dc:creator>Matt Hamilton</dc:creator>
      <pubDate>Mon, 07 Jun 2021 19:38:55 +0000</pubDate>
      <link>https://dev.to/ripplexdev/a-vision-for-federated-sidechains-on-the-xrp-ledger-2o7o</link>
      <guid>https://dev.to/ripplexdev/a-vision-for-federated-sidechains-on-the-xrp-ledger-2o7o</guid>
      <description>&lt;p&gt;&lt;em&gt;Today, RippleX is rolling out a community page on DEV aimed at engaging the growing XRP Ledger Community.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Our inaugural post was &lt;a href="https://blog.ripplex.io/a-vision-for-federated-sidechains-xrp-ledger/" rel="noopener noreferrer"&gt;written&lt;/a&gt; by David Schwartz, CTO at Ripple and one of the original architects of the XRP Ledger, and introduces his vision for Federated Sidechains.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Developers around the world are invited to share ideas, provide feedback, ask questions and join the discussion. Together, we look forward to building trust and utility for the XRP Ledger.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Over the last nine years, the XRP community has been committed to advancing the innovation and forward progress of the &lt;a href="https://xrpl.org/" rel="noopener noreferrer"&gt;XRP Ledger (XRPL)&lt;/a&gt; to dramatically increase its decentralization, performance, and feature set.&lt;/p&gt;

&lt;p&gt;Among the most-requested features we have heard from developers and contributors to the XRP Ledger is smart contract &lt;a href="https://dev.to/wietse/hooked-1-smart-contracts-on-the-xrp-ledger-5eb6"&gt;capabilities&lt;/a&gt; brought about by the exponential growth in decentralized finance (DeFi). In fact, the number of DeFi developers has grown &lt;a href="https://medium.com/electric-capital/electric-capital-developer-report-2020-9417165c6444" rel="noopener noreferrer"&gt;110%&lt;/a&gt; since 2019, and that number is projected to grow well beyond 2021. However, we at Ripple have long advocated against features that would compromise the XRP Ledger's highly efficient focus on payments.&lt;/p&gt;

&lt;p&gt;Today, we are proposing a strategy that enables the best of both worlds: Federated Sidechains for the XRP Ledger. This will enable developers to implement new features, such as native smart contracts that interoperate seamlessly with XRP and the XRP Ledger, while also allowing the XRP Ledger to maintain its existing, "lean and efficient" feature set.&lt;/p&gt;

&lt;p&gt;Federated Sidechains allow for experimentation and specialization, so developers can enjoy the power of the XRPL on a sidechain that acts as its own blockchain. For example, imagine the potential to branch out into new functionality by slimming down the XRPL's features to a specific subset for a particular use case—or even creating a private, parallel network for a permissioned blockchain. Federated Sidechains could very well make this a reality.&lt;/p&gt;

&lt;h2&gt;
  
  
  How It Works
&lt;/h2&gt;

&lt;p&gt;In order to understand the vision for Federated Sidechains, it is first important to define a federator: a piece of software that connects to at least two instances of the XRPL software. The federator software means anyone who wanted to could run a sidechain to the XRP Ledger. On one side, the federator is connected to XRP Ledger Mainnet. On the other side, it connects to one or more sidechains. The federator would be run only by parties who operate &lt;a href="https://xrpl.org/run-rippled-as-a-validator.html" rel="noopener noreferrer"&gt;validators&lt;/a&gt; on at least one sidechain.&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.amazonaws.com%2Fuploads%2Farticles%2Fzlinl2qia2opuhfamvn2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzlinl2qia2opuhfamvn2.png" alt="Sidechain diagram" width="766" height="308"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The vision is that each sidechain would function as its own blockchain. They’d have their own ledger and transactions just as the XRP Ledger does. What makes them sidechains is the federation system which allows XRP and issued tokens to move from one chain to another.&lt;/p&gt;

&lt;p&gt;Federated Sidechains could use XRP as their primary asset. In that case, people could use the federation system to move XRP from XRPL to the sidechain. Then, the moved XRP could be used on the sidechain just as it is on the main chain. Anyone could move XRP from either chain to the other.&lt;/p&gt;

&lt;p&gt;Alternatively, sidechains could use their own native asset, so people with accounts on both ledgers could move XRP to and from the issued asset on the sidechain.&lt;/p&gt;

&lt;h3&gt;
  
  
  Functionality:
&lt;/h3&gt;

&lt;p&gt;Federated assets imported onto XRPL itself would trade on the XRPL’s integrated &lt;a href="https://xrpl.org/decentralized-exchange.html" rel="noopener noreferrer"&gt;decentralized exchange (DEX)&lt;/a&gt;. XRP imported onto sidechains would be used for liquidity on their integrated DEX as well.&lt;/p&gt;

&lt;p&gt;This strategy requires three things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Building a new piece of software, or the “federator.”&lt;/li&gt;
&lt;li&gt;Making two trivial changes to the operation of the live XRP Ledger network.&lt;/li&gt;
&lt;li&gt;Adding new features to the XRPL server software to allow it to operate in a sidechain. However, these features would not be enabled on XRPL itself. (The current recommendation is to fork the XRPL software so that new versions of the sidechain software could come out without having to make new versions of the XRPL software and to reduce the risk of harming XRPL.)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Each sidechain would have a "trust" account on the XRPL Mainnet. This account can hold assets on the XRPL on behalf of users of the sidechain. The account would use a &lt;a href="https://xrpl.org/multi-signing.html#multi-signing" rel="noopener noreferrer"&gt;multisign&lt;/a&gt; or threshold key with the signers being the validators of the sidechain. Each sidechain validator operator registers a &lt;a href="https://blog.ripplex.io/ripple-keypairs-xrp-ledger-key-generation-and-signing/" rel="noopener noreferrer"&gt;signing key&lt;/a&gt; that signs transactions on XRPL; thus, the validators of the sidechain can collectively create transactions to manage the sidechain's Mainnet account.&lt;/p&gt;

&lt;p&gt;The XRP Ledger Mainnet has one native asset, XRP, and an unlimited number of issued tokens that can represent anything else but don't have the same status as XRP. It wouldn't make sense for each sidechain to start with a whole new set of 100 billion XRP, so instead, sidechains have two options for their native asset: either have a new native asset for the sidechain, or set aside some real XRP for use on the sidechain. If the sidechain uses XRP as its native asset, then the chain’s account on the Mainnet holds the sidechain's total amount of XRP "in trust" for use in the sidechain. If the sidechain creates a different native asset, that asset can be issued on XRPL Mainnet by the sidechain's Mainnet account.&lt;/p&gt;

&lt;p&gt;The sidechain can hold other assets and tokens issued natively on the XRPL Mainnet; just like with XRP, the sidechain's Mainnet account holds the total amount in use on the sidechain. The ownership of that asset within the sidechain can change as a result of transactions and events in the sidechain that the XRPL Mainnet never needs to see. Whenever an asset—XRP or otherwise—needs to move "out of" the sidechain, the sidechain's Mainnet account sends that amount of XRP to its intended recipient on the Mainnet. This could even be another sidechain's account, allowing assets to cross from one sidechain through the Mainnet to any other sidechain. Conversely, to send funds "into" a sidechain, you would send funds to that sidechain's Mainnet account.&lt;/p&gt;

&lt;p&gt;Someone who establishes a new sidechain should pick a set of initial validators and have them negotiate appropriate threshold or multi-signing keys. They would then create the sidechain’s XRPL Mainnet account and set it up so that only the sidechain validators' collective signing power can control that account. If the sidechain's validators change, then the Mainnet account should change its keys to match the new list of trusted validators. (Note: The XRP Ledger's native multi-signing lists are limited to 8 keys or fewer, but threshold keys can support as many signers as necessary for each of the sidechain's validators to be included).&lt;/p&gt;

&lt;h2&gt;
  
  
  Advantages
&lt;/h2&gt;

&lt;p&gt;With this software, anyone can choose to run a sidechain to the XRP Ledger. For developers, it unlocks new use cases like native DeFi capabilities and smart contracts. Developers can also build and launch blockchain features that are “baked” into these sidechains; in the future, successful features could even be ported to the XRPL Mainnet.&lt;/p&gt;

&lt;p&gt;The developers managing a sidechain also have the freedom to decide how their chains work. They would choose their own validators for their sidechain and could change the system’s rules as they need (with the cooperation of their sidechain's validators). For example, a sidechain could operate without transaction fees or reserve requirements, it could operate without its own copy of the XRP Ledger's decentralized exchange, or it could add new transaction types and functionality for storing large chunks of data on-ledger. The possibilities are limitless: a sidechain can be strictly permissioned or (nearly) permissionless, centralized or (mostly) decentralized. You could even run a sidechain temporarily while letting it manage real value and gracefully shut it down after it has served its purpose.&lt;/p&gt;

&lt;p&gt;Immediate advantages of Federated Sidechains for developers include:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Horizontal scaling&lt;/strong&gt;: Sidechains can have their own fee system, their own reserve system, and their own transaction capacity. Someone who wants to create a system with thousands of users that can hold XRP has a better option than being the custodian or putting all the accounts on XRPL directly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Low risk&lt;/strong&gt;: The XRP Ledger doesn't need to change at all. Even the changes that would be helpful are quite minimal.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Low effort&lt;/strong&gt;: Anyone who needs or wants to experiment with a blockchain can get started with a complete system ready out of the box, based on powerful, stable, and sustainable XRP Ledger technology.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Long roadmap&lt;/strong&gt;: New features can be added over a long period of time-based on feedback on what people find interesting. This would be a continuous stream of new features and capabilities.&lt;/p&gt;

&lt;h2&gt;
  
  
  Changes to the XRP Ledger
&lt;/h2&gt;

&lt;p&gt;Succeeding in this vision requires a few changes to the XRPL software that wouldn’t be used on XRPL itself in order to support the sidechain features. The primary change to the software would be to support the &lt;a href="https://xrpl.org/technical-faq.html#validators-and-unique-node-lists" rel="noopener noreferrer"&gt;unique node list (UNL)&lt;/a&gt; being stored in the ledger. Pseudo-transactions to change the UNL would be needed. A “hint” UNL would need to be supported to avoid the chicken and egg problem of needing the UNL to get the ledger and the ledger to get the UNL.&lt;/p&gt;

&lt;p&gt;Support for the coordination of creating threshold and/or multisign keys and signing XRPL transactions introduced by the federator is also necessary. Some API enhancements would likely be needed to handle pseudo-transactions introduced by the federator or federator-federator communication through the peer network.&lt;/p&gt;

&lt;p&gt;The XRP Ledger mainnet could also use a flag to indicate whether an issued asset was permitted to federate or not. Some asset issuers, for example, might insist that all holders of their assets be directly represented on the main chain for regulatory purposes while others could allow their assets to freely trade on sidechains. (It's always possible to privately allocate some of your own resources to others, with or without a sidechain to automate the process, but the legal responsibilities of doing so can vary based on jurisdiction and circumstances.)&lt;/p&gt;

&lt;p&gt;Sidechains would have a special entry in their ledgers that tracks the last sidechain transaction that has been executed on the main chain and the last main chain transaction that has been executed on the sidechain.&lt;/p&gt;

&lt;p&gt;When federators see a new transaction on the sidechain that affects the main chain, they coordinate the submission of that transaction to the main chain. When federators see a new transaction on the main chain that affects the sidechain, they coordinate the submission of that transaction to the main chain.&lt;/p&gt;

&lt;p&gt;Making these changes is probably the biggest part of this effort because even though they won’t be enabled on XRPL, there is still risk associated with changing the software. For example, some existing code may need to be moved or adjusted which carries the risk of inadvertently changing behavior.&lt;/p&gt;

&lt;p&gt;The outlined strategy is a starting point to gather feedback from the XRP Ledger community. We invite developers and contributors to the community to comment below. Let’s build a roadmap for innovative, new use cases together.&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>xrpl</category>
      <category>blockchain</category>
      <category>cryptocurrency</category>
    </item>
    <item>
      <title>My Setup for Streaming Livecoding</title>
      <dc:creator>Matt Hamilton</dc:creator>
      <pubDate>Fri, 18 Dec 2020 12:47:52 +0000</pubDate>
      <link>https://dev.to/ibmdeveloper/my-setup-for-streaming-livecoding-4k37</link>
      <guid>https://dev.to/ibmdeveloper/my-setup-for-streaming-livecoding-4k37</guid>
      <description>&lt;p&gt;This is a video showcasing the setup I have for streaming live-coding sessions. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://cinnamon.video/watch?v=477254144894174297" rel="noopener noreferrer"&gt;A 1080p version of this video is available here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this video I cover three main areas:&lt;/p&gt;

&lt;h2&gt;
  
  
  What I want to achieve and why?
&lt;/h2&gt;

&lt;p&gt;You've no doubt seen plenty of live-streamed videos with a screen capture taking up much of the screen and a small disconnected head in the bottom corner of the presenter talking away. My goal in this setup is to make my session much more engaging. One of the main advantages of streaming live-coding is the audience gets to not only see &lt;em&gt;what&lt;/em&gt; you produce but &lt;em&gt;how&lt;/em&gt; you go about it. What are your thought processes? What mistakes you make. How you go about solving a problem. &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.amazonaws.com%2Fi%2Fy0nqzgxscmzo7tq64zly.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fy0nqzgxscmzo7tq64zly.png" alt="View of the live streaming session" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Also, as a developer presenting, I have to speak my mind out loud for the audience as I go along, and this helps me to reflect on my own understanding. Similar in fashion to &lt;a href="https://en.wikipedia.org/wiki/Rubber_duck_debugging" rel="noopener noreferrer"&gt;"rubber duck" debugging&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In this setup, I try to achieve a much more engaging format by orienting the camera, the screen, and myself in such a way that my eye line follows the code. It is much more engaging for the audience that my eyes actually look towards the line of code I'm working on and talking about. It gives them a much better feeling of actually being there with me, looking over my shoulder as I'm coding.&lt;/p&gt;

&lt;p&gt;I want to try and replicate a feeling a bit like the big transparent lightboards you see. These have a presenter behind a glass panel drawing on the panel with fluorescent markers and a camera on the other side. However, they require physically a lot of space and setup so not suitable to do in a home-office environment. &lt;/p&gt;

&lt;h2&gt;
  
  
  Physical Setup
&lt;/h2&gt;

&lt;p&gt;I have my camera (Logitech c920) mounted at eye-level to the side of my monitor in such a way that the geometry of my eyes, the screen, and the camera produce the effect that I am looking sideways slightly, towards the code.&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.amazonaws.com%2Fi%2Fn8gwr4ojrhe4aes0lwvm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fn8gwr4ojrhe4aes0lwvm.png" alt="Behind the Scenes view" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I have some home-made light panels that I use and have a pipe-frame on my desk that my monitor, lights, and cameras are all mounted to. &lt;a href="https://dev.to/cassieview/make-a-custom-pipe-desk-mount-29i9"&gt;This idea was taken from another developer advocate, Cassie&lt;/a&gt;. This means that I can raise my sit-stand desk to standing and everything goes up with it and is still at eye level.&lt;/p&gt;

&lt;p&gt;I have an external USB microphone (AKG Perception 120) mounted on an arm that I can position just out of shot.&lt;/p&gt;

&lt;h2&gt;
  
  
  OBS Setup
&lt;/h2&gt;

&lt;p&gt;I use &lt;a href="https://obsproject.com/" rel="noopener noreferrer"&gt;OBS - Open Broadcaster Software&lt;/a&gt; to do my streaming. It allows you to create scenes with multiple input sources, such as screen capture and webcam feeds.&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.amazonaws.com%2Fi%2Fxqqtyfkiwyvsmlzwhg66.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxqqtyfkiwyvsmlzwhg66.png" alt="Setting a filter on OBS" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I have two monitors, the built-in screen on my Macbook and an external 1080p monitor above it. I arrange my screens such that what I am presenting (a terminal, a web browser, slides, etc) are all arranged on the lower screen and each full screen on a separate space. I can then use four fingers to swipe on the touchpad to move between them.&lt;/p&gt;

&lt;p&gt;I have OBS and anything I &lt;em&gt;don't&lt;/em&gt; want the audience to see on the top screen. So that includes my Slack workspaces, email, the Twitch channel management page, etc.&lt;/p&gt;

&lt;p&gt;When presenting I am looking at the top screen, at the OBS preview which means my head is up and I'm not just looking down with the audience just seeing the top of my head. It also means I see the preview of the effect of myself behind the code when I point at the code, which means I can accurately look and point at the parts I'm talking about.&lt;/p&gt;

&lt;p&gt;Anyway, enjoy the video and I hope it gives you some ideas on making your streaming more engaging.&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>twitch</category>
      <category>devrel</category>
      <category>obs</category>
    </item>
  </channel>
</rss>
