<?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: sirmos</title>
    <description>The latest articles on DEV Community by sirmos (@sirmos).</description>
    <link>https://dev.to/sirmos</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%2F3976611%2F3965321d-0451-46f3-912a-ce679190302c.jpeg</url>
      <title>DEV Community: sirmos</title>
      <link>https://dev.to/sirmos</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sirmos"/>
    <language>en</language>
    <item>
      <title>Manrova: What We Learned Building a Multi Agent System That Watches, Doesn't Just Answers</title>
      <dc:creator>sirmos</dc:creator>
      <pubDate>Sun, 30 Aug 2026 18:35:47 +0000</pubDate>
      <link>https://dev.to/sirmos/manrova-what-we-learned-building-a-multi-agent-system-that-watches-doesnt-just-answers-592g</link>
      <guid>https://dev.to/sirmos/manrova-what-we-learned-building-a-multi-agent-system-that-watches-doesnt-just-answers-592g</guid>
      <description>&lt;p&gt;&lt;em&gt;This post was created for the purpose of entering the All Things Agentic Hackathon.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The question that started it
&lt;/h2&gt;

&lt;p&gt;Most agent demos answer a question you already knew to ask. Manrova started from a different question: what if the hard part isn't answering, it's noticing?&lt;/p&gt;

&lt;p&gt;A vessel produces a constant stream of operational signals: GPS and radar position, crew watch schedules, near-miss reports, compliance records. None of that is missing information. The problem is that nobody has time to correlate four different systems, for every vessel, every day, before a small disagreement becomes an incident report instead of a warning.&lt;/p&gt;

&lt;p&gt;So instead of building a chatbot that waits to be asked, we built a system of agents whose job is to watch continuously, investigate when something looks off, coordinate with each other, and only interrupt a human when a decision genuinely needs one.&lt;/p&gt;

&lt;h2&gt;
  
  
  The shape of the system
&lt;/h2&gt;

&lt;p&gt;Manrova has four specialist agents and one orchestrator, the Officer of the Watch (OOW).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;Navigation Integrity Agent&lt;/strong&gt; checks whether GPS and radar-derived position actually agree.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;Crew Readiness Agent&lt;/strong&gt; looks at rest and duty patterns for fatigue risk.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;Fleet Pattern Agent&lt;/strong&gt; scans near-miss history across the whole fleet, not just one vessel.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;Compliance Readiness Agent&lt;/strong&gt; reasons about certificate exposure relative to a vessel's actual schedule, not just a raw expiry date.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of them work in isolation. When the Navigation Integrity Agent flags something, the Officer of the Watch decides what other context is worth pulling in, correlates the evidence, and runs it through deterministic risk logic to settle on an overall severity. Below a threshold, Manrova keeps watching, silently. Above it, the OOW prepares a response and stops, waiting for a human to approve anything that goes out externally.&lt;/p&gt;

&lt;p&gt;That gate was the single most important design decision in the whole project: &lt;strong&gt;the system assists the watch. It does not replace the watch.&lt;/strong&gt; &lt;br&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%2Fctummcmlwreao1kprlt6.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fctummcmlwreao1kprlt6.jpg" alt=" " width="611" height="573"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The design choice we'd defend the hardest
&lt;/h2&gt;

&lt;p&gt;Safety-critical math never touches a language model. Position deviation, weighted risk scoring, incident state transitions: all deterministic Python, computed the same way every time, auditable, reproducible. The LLM layer sits on top of that structured output, interpreting it and narrating it in plain language for a fleet operator.&lt;/p&gt;

&lt;p&gt;It would have been faster to just hand raw telemetry to a model and ask it to decide. It also would have been the wrong call for a system where a false negative has real consequences. Deterministic logic draws the boundary. The agents interpret what's inside it. A human holds final authority when the boundary is crossed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building the enterprise trust layer for real
&lt;/h2&gt;

&lt;p&gt;For the Fortified Enterprise Fleet track, we didn't want to just describe these components conceptually, we wanted them actually running.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Agent Registry&lt;/strong&gt;: all five agents (four specialists plus the OOW) are published to a live Firestore collection, versioned, with the exact permissions each one is allowed to exercise.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Agent Gateway&lt;/strong&gt;: every specialist call is routed through a policy check against that registry before it's allowed through.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Model Armor&lt;/strong&gt; (our own guardrail implementation of the same pattern): any untrusted free text, like a near-miss report description, is screened for prompt injection and has PII redacted before it ever reaches a model.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Agent Observability&lt;/strong&gt;: every investigation is wrapped in OpenTelemetry trace spans, so the full reasoning chain is inspectable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Memory Bank&lt;/strong&gt;: completed investigations persist in Firestore, so a vessel's history survives across sessions instead of resetting on every request.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Agent Identity&lt;/strong&gt;: each agent runs under its own IAM service account, least-privilege, rather than one shared credential doing everything.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Real data, not just demo data
&lt;/h2&gt;

&lt;p&gt;It bothered us that most hackathon demos run on the same three lines of fixture data forever. Manrova's live site supports two paths: a one-click fixed demo scenario, and a real registration flow where any fleet operator can register, add a vessel (a real name or an internal alias, never required to disclose a hull identity), and run an investigation on genuinely entered navigation and crew data. For testing, we used public AIS-derived position data for a real, currently operating vessel as the basis for a realistic scenario, clearly separated from the synthetic demo data used elsewhere in the app. &lt;br&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%2Fmusfnvg032lweo4llpqh.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%2Fmusfnvg032lweo4llpqh.png" alt=" " width="800" height="370"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What surprised us
&lt;/h2&gt;

&lt;p&gt;We expected the hard part to be prompt engineering. It wasn't. The hard part was deciding, agent by agent, exactly what each one was allowed to trust, when it should hand off to another agent, and where control had to return to a human no matter what the model said. Getting that division of responsibility right mattered more than any single prompt.&lt;/p&gt;

&lt;p&gt;We also came away convinced that deterministic logic and agentic reasoning aren't competitors. They're better together than either one trying to do the whole job: the deterministic layer sets the boundary, the agents interpret what's happening inside it, and a human holds the final call when the situation actually calls for one.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Live site: &lt;a href="https://manrova.vercel.app" rel="noopener noreferrer"&gt;manrova.vercel.app&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Source: &lt;a href="https://github.com/serinalapoez/Manrova" rel="noopener noreferrer"&gt;github.com/serinalapoez/Manrova&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Built with Gemini (3.5+) via Google's Agent Development Kit, with Firestore as the persistence layer, and a parallel implementation on AWS Strands Agents SDK running on Amazon Bedrock.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>googlecloud</category>
      <category>opensource</category>
      <category>agents</category>
    </item>
    <item>
      <title>Three fields, three different errors, and the bug wasn't mine</title>
      <dc:creator>sirmos</dc:creator>
      <pubDate>Wed, 12 Aug 2026 07:31:11 +0000</pubDate>
      <link>https://dev.to/sirmos/three-fields-three-different-errors-and-the-bug-wasnt-mine-32p5</link>
      <guid>https://dev.to/sirmos/three-fields-three-different-errors-and-the-bug-wasnt-mine-32p5</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for &lt;a href="https://dev.to/bugsmash"&gt;DEV's Summer Bug Smash: Smash Stories&lt;/a&gt; powered by &lt;a href="https://sentry.io/" rel="noopener noreferrer"&gt;Sentry&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;Brickwarden has two agents. &lt;br&gt;
One builds a tokenized asset on Ethereum Sepolia. &lt;br&gt;
The other watches it and can freeze or burn tokens on its own if something looks wrong. Every other piece worked, tokenize, launch, whitelist, mint, all three of Warden's compliance triggers. &lt;br&gt;
The last piece was dividends, and it turned into a two week standoff with one API call.&lt;/p&gt;

&lt;h2&gt;
  
  
  The bug that wasn't a bug
&lt;/h2&gt;

&lt;p&gt;Paying out dividends meant approving a stablecoin allowance first, so the contract could pull funds from the wallet. &lt;br&gt;
The docs gave a clean example payload. I matched it exactly.&lt;/p&gt;

&lt;p&gt;It came back with:&lt;br&gt;
"messages": "Tokenizer address is required if token symbol is one of BKN/USDT/USDC"&lt;/p&gt;

&lt;p&gt;Fine, add the field. Retried.&lt;/p&gt;

&lt;p&gt;"messages": "User not found"&lt;/p&gt;

&lt;p&gt;Same wallet. Same address that had signed every other successful call in the project, tokenize, whitelist, mint, all proven on chain. &lt;br&gt;
Tried the field as an email instead of an address. Different error. &lt;br&gt;
Tried both fields together. A third, completely different error:&lt;br&gt;
"messages": "client-signed prepare must return exactly one txId"&lt;/p&gt;

&lt;p&gt;Three fields, three combinations, three unrelated failures.&lt;br&gt;
At that point it stopped looking like something I was getting wrong and started looking like something broken on the other end.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ruling myself out
&lt;/h2&gt;

&lt;p&gt;Before saying that to anyone, I wanted to be sure. &lt;br&gt;
I pulled the token's real spender address straight from Brickken's own &lt;code&gt;get-tokenizer-info&lt;/code&gt; endpoint instead of guessing it. I matched their documented example field for field. Same wallet, same escrow address, same shape as their own docs. &lt;br&gt;
Still "User not found."&lt;/p&gt;

&lt;p&gt;That was the point I wrote up the exact payload and the three error messages and sent it to Brickken's support, instead of trying a fourth combination and hoping.&lt;/p&gt;

&lt;h2&gt;
  
  
  The resolution
&lt;/h2&gt;

&lt;p&gt;A few days later, Davide and the Brickken team confirmed it: a backend bug in the approve flow for shared payment tokens, fixed and deployed to sandbox. Same code, same payload I had already tried and matched to their docs, ran clean the moment their fix landed.&lt;/p&gt;

&lt;p&gt;Approve result:&lt;br&gt;
{&lt;br&gt;
"success": true,&lt;br&gt;
...&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;Dividend distribution went through right after.&lt;/p&gt;

&lt;h2&gt;
  
  
  What stuck with me
&lt;/h2&gt;

&lt;p&gt;The instinct when an API call fails three different ways is to assume you are missing something, and usually you are. But when the exact same wallet, the exact same shape, matching the vendor's own example, produces three unrelated errors across three attempts, that pattern itself is a signal worth trusting. Chasing a fourth field name would have wasted more time than writing up what actually happened and asking. &lt;/p&gt;

&lt;p&gt;Sometimes the fix is not in your code at all, and knowing when to stop debugging and start asking is its own skill.&lt;/p&gt;

&lt;p&gt;Repo: &lt;a href="https://github.com/sirmos/Brickwarden" rel="noopener noreferrer"&gt;https://github.com/sirmos/Brickwarden&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thank you for reading!!!&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>bugsmash</category>
      <category>webdev</category>
      <category>api</category>
    </item>
    <item>
      <title>A one line array check that was hiding a bigger bug</title>
      <dc:creator>sirmos</dc:creator>
      <pubDate>Wed, 12 Aug 2026 07:15:19 +0000</pubDate>
      <link>https://dev.to/sirmos/a-one-line-array-check-that-was-hiding-a-bigger-bug-5bp2</link>
      <guid>https://dev.to/sirmos/a-one-line-array-check-that-was-hiding-a-bigger-bug-5bp2</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for &lt;a href="https://dev.to/bugsmash"&gt;DEV's Summer Bug Smash: Clear the Lineup&lt;/a&gt; powered by &lt;a href="https://sentry.io/" rel="noopener noreferrer"&gt;Sentry&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Project Overview
&lt;/h2&gt;

&lt;p&gt;Brickwarden pairs two agents around one tokenized asset on Ethereum Sepolia, built on Brickken's sandbox API. An Issuer Agent creates the asset, runs the offering, whitelists investors, mints tokens, and pays out dividends. A Warden Agent watches the same asset for compliance triggers and can revoke access or burn tokens on its own the moment something goes wrong, no approval needed from the Issuer.&lt;/p&gt;

&lt;p&gt;Every write action either agent takes, mint, whitelist, burn, approve, goes through one shared helper function that prepares a transaction, signs it locally, and sends it to the chain.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bug Fix or Performance Improvement
&lt;/h2&gt;

&lt;p&gt;That shared helper assumed the API always returns an array of transactions to sign. That held up for months, until one specific call broke it.&lt;/p&gt;

&lt;p&gt;I needed to mint tokens to an investor who was already whitelisted, so I passed &lt;code&gt;needWhitelist: true&lt;/code&gt; anyway, expecting it to just get skipped. Instead the API responded with &lt;code&gt;transactions&lt;/code&gt; as a single object instead of an array, and the loop that signs each transaction crashed with:&lt;br&gt;
Re-mint failed: prepared.transactions is not iterable&lt;/p&gt;

&lt;p&gt;![Terminal showing the crash after two earlier failed attempts, ending in "prepared.transactions is not iterable"]&lt;br&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%2Fr8pwd2e6z4oomracy4ww.webp" 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%2Fr8pwd2e6z4oomracy4ww.webp" alt=" " width="706" height="1568"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nothing in the error pointed at the real cause. I compared the raw response against a normal, working mint call side by side, and the only difference was that one field's shape, an object where an array should have been, and only when that one flag combination fired.&lt;/p&gt;
&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;p&gt;Before:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Signing &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;prepared&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;transactions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; transaction(s)...`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;signedTransactions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tx&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;prepared&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;transactions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;signedTransactions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;signTransaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tx&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;After:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;txList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prepared&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;transactions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;prepared&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;transactions&lt;/span&gt;
  &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;prepared&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;transactions&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Signing &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;txList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; transaction(s)...`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;signedTransactions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tx&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;txList&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;signedTransactions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;signTransaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tx&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;Full source: &lt;a href="https://github.com/sirmos/Brickwarden/blob/main/src/brickkenRest.js" rel="noopener noreferrer"&gt;https://github.com/sirmos/Brickwarden/blob/main/src/brickkenRest.js&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  My Improvements
&lt;/h2&gt;

&lt;p&gt;I could have special cased this one call and moved on, but the helper is shared across every write action in the project, so a narrow fix would only have delayed the next time this shape showed up somewhere else. The &lt;code&gt;Array.isArray&lt;/code&gt; check normalizes the response once, at the one place all of them pass through, so every call benefits from the same guard instead of needing its own workaround.&lt;/p&gt;

&lt;p&gt;I also logged the raw prepared response before touching it, rather than guessing from the error text alone. The error said "not iterable," which explains what broke but not why. Seeing the actual shape next to a working response made the real cause obvious in one comparison instead of several rounds of trial and error.&lt;/p&gt;

&lt;p&gt;Thank you for reading!!!&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>bugsmash</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>I built a dApp that fixes the savings system my community has trusted for several years</title>
      <dc:creator>sirmos</dc:creator>
      <pubDate>Fri, 10 Jul 2026 14:22:43 +0000</pubDate>
      <link>https://dev.to/sirmos/i-built-a-dapp-that-fixes-the-savings-system-my-community-has-trusted-for-several-years-4bfj</link>
      <guid>https://dev.to/sirmos/i-built-a-dapp-that-fixes-the-savings-system-my-community-has-trusted-for-several-years-4bfj</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for &lt;a href="https://dev.to/challenges/weekend-2026-07-09"&gt;Weekend Challenge: Passion Edition&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;I grew up watching the women in my family do ajo.&lt;/p&gt;

&lt;p&gt;Every month, a group of people pool money together. One person gets the full pot. Then the next. Then the next. No bank. No interest. Just trust.&lt;/p&gt;

&lt;p&gt;It's been working in Nigeria for centuries.&lt;/p&gt;

&lt;p&gt;But the trust part? That's where it breaks.&lt;/p&gt;

&lt;p&gt;The collector - the person who holds everyone's money, can disappear the moment they've received their own payout. No receipt. No contract. No way to get your money back.&lt;/p&gt;

&lt;p&gt;I know people who've lost hundreds of thousands of naira this way. And they still go back, because the system itself is genius. The only broken part is the human in the middle.&lt;/p&gt;

&lt;p&gt;That's what drove me to build EsusuX.&lt;/p&gt;

&lt;p&gt;EsusuX is a decentralized ajo protocol on Solana. It replaces the collector with a smart contract. The contract holds the money. Not me. Not a company. A program on the blockchain that has one job, follow the rules.&lt;/p&gt;

&lt;p&gt;Here's how it works:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Someone creates a savings circle and sets the amount, number of members, and frequency&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Members join by connecting their wallet and locking a small collateral deposit &lt;br&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%2F76ak9gwa6q59bdsmu4s8.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%2F76ak9gwa6q59bdsmu4s8.png" alt=" " width="685" height="522"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Every round, members contribute USDC to the contract&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The contract automatically pays out the full pool to that round's member&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If someone defaults after receiving their payout, their collateral is slashed&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No collector. No trust required. No one can run.&lt;br&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%2F5lkowuwn56p5b6rv7luj.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%2F5lkowuwn56p5b6rv7luj.png" alt=" " width="800" height="424"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;Live app: &lt;a href="https://esusux.vercel.app" rel="noopener noreferrer"&gt;esusux.vercel.app&lt;/a&gt;&lt;br&gt;
  &lt;iframe src="https://www.youtube.com/embed/VklQ9s9QsEs"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Smart contract deployed on Solana devnet:&lt;br&gt;
Program ID: CG2XsN5oeS1QzEUn3cuaqJb67uaAXgxMpPYsD9Qv5wJp&lt;br&gt;
Connect a Phantom or Solflare wallet, create a circle, and join one right now using devnet USDC from &lt;a href="https://faucet.circle.com" rel="noopener noreferrer"&gt;faucet.circle.com&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/sirmos" rel="noopener noreferrer"&gt;
        sirmos
      &lt;/a&gt; / &lt;a href="https://github.com/sirmos/esusux" rel="noopener noreferrer"&gt;
        esusux
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;esusux&lt;/h1&gt;

&lt;/div&gt;
&lt;/div&gt;



&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/sirmos/esusux" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;p&gt;I chose Solana because the math only works here.&lt;/p&gt;

&lt;p&gt;A ₦2,000 weekly contribution cannot survive Ethereum gas fees. On Solana, the transaction fee is a fraction of a cent. Payments confirm in under a second. For a savings app targeting everyday Nigerians, that's not a nice to have. It's the whole thing.&lt;/p&gt;

&lt;p&gt;The smart contract is written in Rust using the Anchor framework. Three core instructions power the protocol:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;create_circle&lt;/strong&gt; - the organizer sets contribution amount, number of members, and payout interval. Everything is locked onchain and immutable once set.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;join_circle&lt;/strong&gt; - members join by locking 10% collateral in USDC. The circle automatically activates when all slots are filled.&lt;br&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%2Fk3rn1l44yp8t2q6w1fo3.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%2Fk3rn1l44yp8t2q6w1fo3.png" alt=" " width="513" height="608"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;contribute_and_disburse&lt;/strong&gt; - members send their contribution each round. The contract immediately disburses the full pool to that round's recipient based on join order. No manual trigger. No human decision.&lt;/p&gt;

&lt;p&gt;The frontend is built with Next.js and connects to the program using Anchor's TypeScript SDK. Wallet connection uses the Solana wallet adapter, supporting Phantom and Solflare. Contributions use devnet USDC via Solana Pay, with a QR code members can scan to contribute directly from their phone.&lt;/p&gt;

&lt;p&gt;The whole stack is open source.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prize Categories
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Best Use of Solana&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;EsusuX is built entirely on Solana. The core protocol lives in a Solana program written with Anchor. Every circle creation, member join, and payout disbursement is an on-chain transaction. Solana's low fees and fast finality are what make this viable for small everyday contributions, something that simply isn't possible on other chains.&lt;/p&gt;

&lt;p&gt;Built with: Solana, Anchor, Rust, Next.js, USDC, Solana Pay, Phantom, Solflare, Jupiter Wallet&lt;/p&gt;

&lt;h1&gt;
  
  
  weekendchallenge #solana #web3 #nigeria #defi #EsusuX #weekendchallenge
&lt;/h1&gt;

</description>
      <category>devchallenge</category>
      <category>weekendchallenge</category>
    </item>
    <item>
      <title>How I Built a Digital Estate Manager with Vercel v0 and Amazon Aurora PostgreSQL published</title>
      <dc:creator>sirmos</dc:creator>
      <pubDate>Wed, 17 Jun 2026 09:16:28 +0000</pubDate>
      <link>https://dev.to/sirmos/how-i-built-a-digital-estate-manager-with-vercel-v0-and-amazon-aurora-postgresqlpublished-3o5i</link>
      <guid>https://dev.to/sirmos/how-i-built-a-digital-estate-manager-with-vercel-v0-and-amazon-aurora-postgresqlpublished-3o5i</guid>
      <description>&lt;p&gt;&lt;em&gt;I created this piece of content for the purposes of entering the H0 Hack the Zero Stack Hackathon.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Live app: &lt;a href="https://memoris-sigma.vercel.app" rel="noopener noreferrer"&gt;https://memoris-sigma.vercel.app&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  It started with a death in the family
&lt;/h2&gt;

&lt;p&gt;Two years ago a close friend lost his father suddenly. His father was an organised man but when he died, the family discovered he had 17 online accounts nobody could access. A bank account with money in it. A crypto wallet with a seed phrase nobody could find. An email full of insurance policies and property documents, completely locked.&lt;/p&gt;

&lt;p&gt;His wife spent four months writing letters to companies and crying on phone calls with customer support agents reading from scripts. Some accounts were closed with money still inside them. Some are locked to this day.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"He was the most organised man I knew," she said. "But he never thought about this."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Nobody does. We spend our whole lives building a digital world and we leave no instructions for the people who love us. When the H0 Hackathon came along, I knew exactly what I wanted to build.&lt;/p&gt;

&lt;p&gt;I built &lt;strong&gt;Memoris&lt;/strong&gt;. &lt;br&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%2Fm293ns18rprahvdgi3s4.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%2Fm293ns18rprahvdgi3s4.png" alt=" " width="800" height="407"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What is Memoris?
&lt;/h2&gt;

&lt;p&gt;Memoris is a digital estate manager. It helps you answer one simple question that nobody wants to think about but everyone needs to:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If I died tomorrow, would my family know what to do with my digital life?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;With Memoris you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add all your digital accounts: email, bank, crypto, streaming, social media&lt;/li&gt;
&lt;li&gt;Write encrypted access instructions: passwords, PINs, seed phrases, recovery codes&lt;/li&gt;
&lt;li&gt;Assign each account to a specific person who should receive it&lt;/li&gt;
&lt;li&gt;Add trusted verifiers: people like your pastor, lawyer, or sibling who confirm your passing&lt;/li&gt;
&lt;li&gt;Write last wishes: a personal message your family reads after you are gone 
&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%2Fuvuoqswfc6m1l6p35na0.png" alt=" " width="800" height="368"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you die, your verifiers receive a simple email with one button to click. When all of them confirm, the vault unlocks. Each beneficiary sees only what was assigned to them. Your wife gets the Gmail and the bank instructions. Your son gets the crypto wallet and the seed phrase. Your daughter gets the family photos folder. &lt;br&gt;
Nobody has to guess. Nobody has to fight. Nobody has to spend four months crying on phone calls.&lt;br&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%2Fevz5jhene285vou5hx2a.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%2Fevz5jhene285vou5hx2a.png" alt=" " width="799" height="315"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The problem is bigger than most people realise
&lt;/h2&gt;

&lt;p&gt;When I started researching this, I thought it was a niche problem. I was wrong.&lt;/p&gt;

&lt;p&gt;The average person today has over 100 online accounts. 4.9 billion people use the internet. Every one of them will die someday. And almost none of them have any plan for what happens to their digital life.&lt;/p&gt;

&lt;p&gt;Think about what lives in your digital accounts right now:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Money&lt;/strong&gt; in bank accounts, PayPal, Binance, Opay, cash apps&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Memories&lt;/strong&gt; photos, videos, messages that exist nowhere else&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Documents&lt;/strong&gt; insurance policies, contracts, receipts, medical records&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Subscriptions&lt;/strong&gt; still charging your family every month after you are gone&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Businesses&lt;/strong&gt; accounts for businesses your family might want to continue&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most of this disappears or becomes inaccessible. Companies have no standard process for death. Some require a death certificate. Some require a court order. Some just close the account and keep the money.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Real example:&lt;/strong&gt; In 2021, a family in the UK discovered their father had over £40,000 in a crypto wallet. He had the wallet. Nobody had the seed phrase. The money is still locked today.&lt;/p&gt;

&lt;p&gt;Memoris exists so that this never has to happen to your family.&lt;/p&gt;




&lt;h2&gt;
  
  
  How I built it
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The frontend: Vercel v0 and Next.js
&lt;/h3&gt;

&lt;p&gt;I started with v0.dev, Vercel's AI powered UI generator. I gave it a detailed prompt describing Memoris and it generated a complete Next.js application in under 60 seconds. A dark, elegant landing page. Clean cards. A sidebar navigation. A warm design that felt right for a product people would use during the hardest moments of their lives.&lt;/p&gt;

&lt;p&gt;I then customised everything, switching to a warm dark brown with gold accents (#C9A86A) that feel premium and trustworthy. I used Playfair Display for the headlines because it feels timeless and dignified. Not clinical. Not corporate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stack:&lt;/strong&gt; Next.js 16 · TypeScript · Tailwind CSS · Lucide icons · Vercel deployment&lt;/p&gt;

&lt;h3&gt;
  
  
  The database: Amazon Aurora PostgreSQL
&lt;/h3&gt;

&lt;p&gt;For the database I chose &lt;strong&gt;Amazon Aurora PostgreSQL on AWS RDS&lt;/strong&gt;. This was not an arbitrary choice.&lt;/p&gt;

&lt;p&gt;Memoris handles deeply relational data. A user has assets. Each asset is assigned to a beneficiary. Each beneficiary is connected to a user. Verifiers are connected to users. The access flow that unlocks the right assets for the right person requires complex join queries with conditional logic. PostgreSQL handles all of this natively and elegantly.&lt;/p&gt;

&lt;p&gt;I have five core tables:&lt;br&gt;
users: id, name, email, password_hash, created_at&lt;/p&gt;

&lt;p&gt;assets: id, user_id, asset_type, label, assigned_to, notes&lt;/p&gt;

&lt;p&gt;beneficiaries: id, user_id, name, email, relationship&lt;/p&gt;

&lt;p&gt;verifiers: id, user_id, name, email, confirmed, token&lt;/p&gt;

&lt;p&gt;wishes: id, user_id, content, updated_at&lt;/p&gt;

&lt;p&gt;Every table uses proper foreign keys with ON DELETE CASCADE so if a user deletes their account, everything cleans up properly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stack:&lt;/strong&gt; Amazon Aurora PostgreSQL · AWS RDS · pg (node-postgres) · bcryptjs · SSL connection&lt;/p&gt;

&lt;h3&gt;
  
  
  Authentication
&lt;/h3&gt;

&lt;p&gt;I built authentication from scratch using &lt;strong&gt;bcryptjs&lt;/strong&gt;. When a user signs up, their password is hashed with a salt factor of 10 before it ever touches the database. The plain text password never gets stored anywhere. Simple, secure and appropriate for a product that handles sensitive information.&lt;/p&gt;

&lt;h3&gt;
  
  
  The API
&lt;/h3&gt;

&lt;p&gt;I built five sets of API routes inside the Next.js app directory:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;/api/auth/signup&lt;/code&gt; creates a new user with hashed password&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/api/auth/signin&lt;/code&gt; verifies credentials and returns user data&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/api/assets&lt;/code&gt; GET, POST, DELETE for the asset vault&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/api/beneficiaries&lt;/code&gt; GET, POST, DELETE for beneficiary management&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/api/verifiers&lt;/code&gt; GET, POST, DELETE for trusted verifiers&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/api/wishes&lt;/code&gt; GET and POST for last wishes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every route checks for a user ID in the request header before doing anything. If it is missing it returns a 401. The API is protected at the data layer, not just the UI.&lt;/p&gt;




&lt;h2&gt;
  
  
  The executor view: what family sees
&lt;/h2&gt;

&lt;p&gt;One of the most important parts of Memoris is the executor view. This is the page beneficiaries access after the vault is unlocked. It shows them only their assigned assets, the access instructions, and the owner's last wishes.&lt;/p&gt;

&lt;p&gt;I designed this page with maximum clarity and minimum friction. When someone is grieving they do not need to figure out a complex interface. They need one clear list: here are your accounts, here are the instructions, here is what they wanted you to know.&lt;/p&gt;

&lt;p&gt;The vault unlocked banner at the top sends one message to the family: &lt;em&gt;he thought of you. He prepared this. You are not alone.&lt;/em&gt; &lt;br&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%2Fusy9r7lpnc0i36spd533.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%2Fusy9r7lpnc0i36spd533.png" alt=" " width="800" height="387"&gt;&lt;/a&gt; &lt;/p&gt;




&lt;h2&gt;
  
  
  Design decisions that matter
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why warm gold instead of blue
&lt;/h3&gt;

&lt;p&gt;Most security apps use blue. Blue says trust me, I am a bank. But Memoris is not a bank. It is something much more human than that.&lt;/p&gt;

&lt;p&gt;I chose warm gold (#C9A86A) and deep brown-black (#0a0908) because this is an app people use while thinking about death. It needs to feel warm. Trustworthy. Like a hand on a shoulder.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why the verifier system matters
&lt;/h3&gt;

&lt;p&gt;I could have built Memoris with a simple timer, if the user does not log in for 6 months, unlock the vault. But timers are dangerous. What if the user is on a long trip? What if they are in hospital?&lt;/p&gt;

&lt;p&gt;The verifier system requires real people who actually knew the deceased to confirm. All of them must agree before anything unlocks. For something this important, that friction is a feature not a bug.&lt;/p&gt;




&lt;h2&gt;
  
  
  The hardest part of building this
&lt;/h2&gt;

&lt;p&gt;The biggest challenge was not the code. It was the emotional weight of the product.&lt;/p&gt;

&lt;p&gt;Every time I designed a new screen I had to ask: what is the person using this feeling right now? When someone fills in the last wishes form they are confronting their own mortality. When a family member opens the executor view they are probably crying.&lt;/p&gt;

&lt;p&gt;Every word in the UI matters. Every button label. I rewrote the copy at least five times.&lt;/p&gt;

&lt;p&gt;On the technical side, the trickiest part was the AWS Aurora connection. The default express configuration uses IAM only authentication which took several attempts to get working from Vercel's serverless functions. I ended up using a standard PostgreSQL RDS instance with password authentication over SSL. Simpler, faster and easier to debug.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The lesson: sometimes the path you are forced onto is the better path.&lt;/em&gt;&lt;/p&gt;




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

&lt;p&gt;&lt;strong&gt;v0 is a genuine superpower for hackathons.&lt;/strong&gt; One detailed prompt and you have a production quality Next.js UI to customise instead of starting from scratch.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Aurora PostgreSQL is the right database for relational data.&lt;/strong&gt; I considered DynamoDB but the moment I drew out the data model I knew it had to be PostgreSQL. Relational integrity matters here.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Build the emotional core first.&lt;/strong&gt; The last wishes feature was the most important feature to build. Without it Memoris is just a password manager. With it, it is something a person would actually use, recommend to their parents, and be grateful exists.&lt;/p&gt;




&lt;h2&gt;
  
  
  What comes next for Memoris
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;AES-256 encryption for asset notes using a user controlled master key&lt;/li&gt;
&lt;li&gt;Real email sending for verifier links using AWS SES&lt;/li&gt;
&lt;li&gt;Two factor authentication for vault owners&lt;/li&gt;
&lt;li&gt;Legal document uploads for wills and insurance policies&lt;/li&gt;
&lt;li&gt;Multi language support starting with Yoruba, Igbo, Hausa and Ibibio for the Nigerian market&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Nigerian market is where I see the biggest immediate opportunity. Millions of families deal with digital estate problems every year and there is no product built for this context with local bank support and local languages.&lt;/p&gt;




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

&lt;p&gt;Memoris is live right now. Sign up, create a vault, add assets, set up beneficiaries and verifiers, and see the full executor view.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Live app:&lt;/strong&gt; &lt;a href="https://memoris-sigma.vercel.app" rel="noopener noreferrer"&gt;https://memoris-sigma.vercel.app&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Source code:&lt;/strong&gt; &lt;a href="https://github.com/sirmos/memoris" rel="noopener noreferrer"&gt;https://github.com/sirmos/memoris&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;You will spend years building your digital life. Spend one afternoon making sure the people you love can find it when you are gone.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;That is what Memoris is for. Not for the person who sets it up. For the wife who is already grieving. For the son who just wants to carry out his father's wishes. For the daughter who wants to read her mother's last message.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Build for the people left behind.&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built for the H0 Hack the Zero Stack Hackathon · #H0Hackathon&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How I Built a Clinical Trial Memory AI Agent with Qwen Cloud in 5 Weeks</title>
      <dc:creator>sirmos</dc:creator>
      <pubDate>Tue, 09 Jun 2026 21:42:02 +0000</pubDate>
      <link>https://dev.to/sirmos/how-i-built-a-clinical-trial-memory-ai-agent-with-qwen-cloud-in-5-weeks-5ehd</link>
      <guid>https://dev.to/sirmos/how-i-built-a-clinical-trial-memory-ai-agent-with-qwen-cloud-in-5-weeks-5ehd</guid>
      <description>&lt;h2&gt;
  
  
  The Problem I Set Out to Solve
&lt;/h2&gt;

&lt;p&gt;Clinical trials run for years. Patient data gets scattered across session notes, emails, and spreadsheets. When a doctor asks "what happened to this patient three months ago?", nobody knows fast enough. Adverse events get missed. Documentation takes hours.&lt;/p&gt;

&lt;p&gt;I built CTMC (Clinical Trial Memory Coordinator) to fix that.&lt;/p&gt;

&lt;h2&gt;
  
  
  What CTMC Does
&lt;/h2&gt;

&lt;p&gt;CTMC is a persistent AI memory system for clinical trial teams:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Every session note is &lt;strong&gt;chunked and embedded&lt;/strong&gt; using Qwen's &lt;code&gt;text embedding-v3&lt;/code&gt; model&lt;/li&gt;
&lt;li&gt;Stored as searchable semantic memory scoped to each patient and trial&lt;/li&gt;
&lt;li&gt;Natural language queries are answered by &lt;strong&gt;qwen-max&lt;/strong&gt; using RAG, grounded in real session data with source citations&lt;/li&gt;
&lt;li&gt;An &lt;strong&gt;anomaly detector&lt;/strong&gt; automatically fires safety alerts on new ingestions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One-click FDA adverse event reports&lt;/strong&gt; generated from memory in seconds&lt;/li&gt;
&lt;li&gt;Full &lt;strong&gt;compliance audit trail&lt;/strong&gt; of every memory read and write&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Tech Stack
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Qwen Cloud&lt;/strong&gt; &lt;code&gt;qwen-max&lt;/code&gt; for synthesis, &lt;code&gt;text-embedding-v3&lt;/code&gt; for semantic embeddings&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Node.js / Express&lt;/strong&gt; backend with custom memory engine&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;React + Vite&lt;/strong&gt; frontend&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Alibaba Cloud ECS&lt;/strong&gt; (Singapore) for deployment&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PM2&lt;/strong&gt; for process management
&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%2Ff3en298p47ff0dtzd9ca.png" alt=" " width="800" height="517"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Memory Pipeline
&lt;/h2&gt;

&lt;p&gt;The core insight: don't store session notes as raw text. Instead:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Chunk notes into semantic units (adverse events, observations, protocol notes)&lt;/li&gt;
&lt;li&gt;Embed each chunk via &lt;code&gt;text-embedding-v3&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;On query, embed the question, rank chunks by cosine similarity&lt;/li&gt;
&lt;li&gt;Feed top-k chunks to &lt;code&gt;qwen-max&lt;/code&gt; with strict grounding instructions&lt;/li&gt;
&lt;li&gt;Return answer with exact session date citations&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This gives you a memory that &lt;strong&gt;never hallucinates&lt;/strong&gt; every answer is traceable to a real session.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Biggest Challenge
&lt;/h2&gt;

&lt;p&gt;Getting the anomaly detector to work reliably. The first version silently returned &lt;code&gt;hasAnomaly: false&lt;/code&gt; on every new session. The fix was tightening the JSON output format in the system prompt, Qwen was wrapping responses in markdown code blocks that broke JSON parsing.&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%2Fy7yglqfbk7i65c8ts0kt.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%2Fy7yglqfbk7i65c8ts0kt.png" alt=" " width="800" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Killer Demo Moment
&lt;/h2&gt;

&lt;p&gt;After ingesting 6 months of patient sessions showing ALT liver enzyme progression (22 → 24 → 31 → 52 → 89 → 112 U/L), asking:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"What adverse events has P042 had and are they getting worse?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The agent recalled the full progression across all sessions, cited each date, and flagged the escalating hepatotoxicity, in under 3 seconds. &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%2Focf1hu671h3zdplr805c.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%2Focf1hu671h3zdplr805c.png" alt=" " width="799" height="370"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;Qwen's &lt;code&gt;text-embedding-v3&lt;/code&gt; model produces high-quality embeddings for clinical text. The cosine similarity ranking consistently surfaced the most relevant chunks even across months of session history.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;qwen-max&lt;/code&gt; model with strict grounding prompts is remarkably reliable at staying within the retrieved context, crucial for clinical applications where hallucination is dangerous.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Live demo:&lt;/strong&gt; &lt;a href="http://47.84.200.111:3001/" rel="noopener noreferrer"&gt;http://47.84.200.111:3001/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/sirmos/ctmc" rel="noopener noreferrer"&gt;https://github.com/sirmos/ctmc&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hackathon:&lt;/strong&gt; Qwen Cloud Global AI Hackathon 2026, MemoryAgent Track&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Built in 5 weeks for the Qwen Cloud Global AI Hackathon. The memory grows smarter with every session and never forgets.&lt;/p&gt;

&lt;h1&gt;
  
  
  qwencloud #alibabacloud #ai #hackathon #clinicaltrials #nodejs #react #h0hackathon
&lt;/h1&gt;

</description>
      <category>h0hackathon</category>
    </item>
  </channel>
</rss>
