<?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: Arun KT</title>
    <description>The latest articles on DEV Community by Arun KT (@arun_kt_bb670b3a571f5efd8).</description>
    <link>https://dev.to/arun_kt_bb670b3a571f5efd8</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%2F3835802%2Fd11b76b7-f221-4cc5-bfdf-7378a6cd99d4.png</url>
      <title>DEV Community: Arun KT</title>
      <link>https://dev.to/arun_kt_bb670b3a571f5efd8</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/arun_kt_bb670b3a571f5efd8"/>
    <language>en</language>
    <item>
      <title>My AI agents kept re-verifying the same work. So I made verification a signed, reusable object</title>
      <dc:creator>Arun KT</dc:creator>
      <pubDate>Sat, 04 Jul 2026 07:16:08 +0000</pubDate>
      <link>https://dev.to/arun_kt_bb670b3a571f5efd8/my-ai-agents-kept-re-verifying-the-same-work-so-i-made-verification-a-signed-reusable-object-2199</link>
      <guid>https://dev.to/arun_kt_bb670b3a571f5efd8/my-ai-agents-kept-re-verifying-the-same-work-so-i-made-verification-a-signed-reusable-object-2199</guid>
      <description>&lt;p&gt;Here's a pattern I kept hitting while running a small fleet of agents:&lt;/p&gt;

&lt;p&gt;Agent A needs market data. It finds a paid API, checks that the endpoint is alive, checks the price, makes the call. Twenty minutes later Agent B needs market data. It finds the same API… and checks that the endpoint is alive, checks the price. Same check, same result, new tokens, new latency, new cost. Multiply by every agent, every task, every session — because agents start cold, they re-derive trust from scratch &lt;em&gt;every single time&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Humans solved this ages ago. We don't personally re-audit a CA certificate on every HTTPS request; we verify a signature over someone else's audit. Agents have no equivalent. Every agent is its own tiny, wasteful certificate authority.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verification as an object, not an act
&lt;/h2&gt;

&lt;p&gt;The fix I landed on: stop treating verification as something each agent &lt;em&gt;does&lt;/em&gt;, and start treating it as something an agent can &lt;em&gt;hold&lt;/em&gt; — a signed,portable, reusable object.&lt;/p&gt;

&lt;p&gt;Concretely: my node continuously probes the paid (x402) agent services my agents actually use — a real HTTP 402 challenge every 10 minutes, recording liveness, latency, and the quoted price. Each probe is published as an attestation:&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;"payload"&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;"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;"erabi.x402.probe/0.1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"slug"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"exa-search"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"{{ts}}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"alive"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"http_status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;402&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"latency_ms"&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="err"&gt;latency&lt;/span&gt;&lt;span class="p"&gt;}},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"price_usd"&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="err"&gt;price&lt;/span&gt;&lt;span class="p"&gt;}},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"window_24h"&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;"probes"&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="err"&gt;probes&lt;/span&gt;&lt;span class="p"&gt;}},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"uptime_pct"&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="err"&gt;uptime&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;"sig"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ed25519:…"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"key"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"…"&lt;/span&gt;&lt;span class="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;The signature is a detached ed25519 over the canonicalized payload (RFC 8785), verifiable against the node's published key. An agent that wants to know "is this API worth paying?" fetches this, verifies one signature, and moves on. No probe, no burned call, no re-derived trust:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl https://erabi-production.up.railway.app/index/v1/services/exa-search/attestation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What {{N_days}} days of not re-verifying looks like
&lt;/h2&gt;

&lt;p&gt;The index currently covers 16 real pay-per-call services (search,&lt;br&gt;
browser automation, market data, inference…). Some things the data&lt;br&gt;
already surfaced:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;{{finding_1 — e.g. "a service listed as live on the x402 Bazaar has been dead for the entire measurement window"}}&lt;/li&gt;
&lt;li&gt;{{finding_2 — e.g. "p50 latencies differ by 8x between services at the same price point"}}&lt;/li&gt;
&lt;li&gt;{{finding_3 — e.g. "one service silently changed its quoted price
mid-week — the attestation history caught it"}}&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everything is public: the human view at&lt;br&gt;
&lt;a href="https://erabi-explorer.vercel.app/services" rel="noopener noreferrer"&gt;https://erabi-explorer.vercel.app/services&lt;/a&gt; , the agent view at&lt;br&gt;
&lt;code&gt;/index/v1/services&lt;/code&gt; (JSON), and each service's attestation endpoint.&lt;/p&gt;

&lt;h2&gt;
  
  
  The bigger point
&lt;/h2&gt;

&lt;p&gt;"Agents re-verify what other agents already verified" is not an x402&lt;br&gt;
problem — it's everywhere. Test results, security scans, dependency&lt;br&gt;
checks, doc freshness: agent fleets redundantly re-derive the same facts because there's no trusted medium of exchange for verification itself.&lt;/p&gt;

&lt;p&gt;Signed attestations are that medium. Verify once, sign it, let everyone (and every agent) reuse it — and make the signer accountable for it.&lt;/p&gt;

&lt;p&gt;The reliability index is my first concrete cut at this, built on an open intent-exchange protocol (Apache-2.0, &lt;a href="https://github.com/HMAKT99/Erabi" rel="noopener noreferrer"&gt;https://github.com/HMAKT99/Erabi&lt;/a&gt; )&lt;br&gt;
where identities are Ed25519 keypairs and outcomes are dual-signed on a public ledger. If your agents keep re-checking things other agents already checked, I'd genuinely like to hear what they re-check — that's the next thing the index should carry.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>webdev</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Apple locked hearing assistance inside AirPods. So I built an open-source version for any earbuds.</title>
      <dc:creator>Arun KT</dc:creator>
      <pubDate>Sat, 04 Jul 2026 06:16:45 +0000</pubDate>
      <link>https://dev.to/arun_kt_bb670b3a571f5efd8/apple-locked-hearing-assistance-inside-airpods-so-i-built-an-open-source-version-for-any-earbuds-2lkh</link>
      <guid>https://dev.to/arun_kt_bb670b3a571f5efd8/apple-locked-hearing-assistance-inside-airpods-so-i-built-an-open-source-version-for-any-earbuds-2lkh</guid>
      <description>&lt;p&gt;In 2024, Apple shipped something genuinely great: AirPods Pro can run a clinical-style hearing test and then act as hearing assistance, tuned to your ears. People love it. There's just one catch — it needs an iPhone to set up, recent AirPods to run, and if you're on Android you get nothing.&lt;/p&gt;

&lt;p&gt;Meanwhile, the average pair of prescription hearing aids costs about &lt;strong&gt;$4,700&lt;/strong&gt;, and surveys show a $1,500 device is simply out of reach for more than half the people who need one. There are a billion-plus Android phones out there, most of them sitting next to a pair of ordinary earbuds that already contain everything you physically need: a microphone, a DAC, and speakers.&lt;/p&gt;

&lt;p&gt;The gap seemed absurd. So I've spent the past weeks building &lt;strong&gt;&lt;a href="https://github.com/HMAKT99/OpenHearing" rel="noopener noreferrer"&gt;OpenHearing&lt;/a&gt;&lt;/strong&gt; — a free, GPLv3 Android app that does the whole pipeline:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Hearing check&lt;/strong&gt; — a pure-tone test using the modified Hughson–Westlake staircase (the same adaptive up-down procedure audiologists use), per ear, per frequency. Or skip it and type in the numbers from a real audiogram.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sound profile&lt;/strong&gt; — the results are fitted into a per-ear gain curve (half-gain rule for v1; NAL-NL2 is a pluggable strategy for later).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real-time assist&lt;/strong&gt; — mic in, per-ear DSP, earbuds out. Quiet speech gets louder. Works with whatever earbuds you already own. No root, no special hardware.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It is very deliberately &lt;strong&gt;not a medical device&lt;/strong&gt; — no diagnosis, no treatment claims, big disclaimer before anything plays a tone. Think of it as the open, inspectable "gateway" tier below real hearing care.&lt;/p&gt;

&lt;p&gt;This post is about the three engineering decisions that turned out to matter most.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. The safety-critical DSP is pure Kotlin — and that's the whole point
&lt;/h2&gt;

&lt;p&gt;An app that amplifies sound directly into human ears has exactly one unforgivable failure mode: being loud when it shouldn't be.&lt;/p&gt;

&lt;p&gt;So the entire signal chain is plain Kotlin with zero Android dependencies, hidden behind a tiny I/O interface. &lt;code&gt;AudioRecord&lt;/code&gt;/&lt;code&gt;AudioTrack&lt;/code&gt; is a dumb shell; everything that can hurt someone is JVM-testable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;input → EQ (your profile) → WDRC compression → feedback guard → master gain → LIMITER → output
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The lookahead limiter is &lt;em&gt;always&lt;/em&gt; the final stage, and its test suite is the release gate. My favorite test names in the repo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;output never exceeds the ceiling even for loud input&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;master gain is hard-capped by safety limits&lt;/code&gt; (requesting +999 dB gets you the cap, not a lawsuit)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;live master gain change never exceeds cap or ceiling&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;NaN and Infinity in → silence out, never noise&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When I later added live gain adjustment (changing volume &lt;em&gt;while&lt;/em&gt; the audio thread is running), the change was a single &lt;code&gt;@Volatile&lt;/code&gt; field read once per block — because the limiter downstream makes it impossible for a mid-stream change to produce anything dangerous. Safety as architecture, not as code review vigilance.&lt;/p&gt;

&lt;p&gt;Every limit lives in one file, &lt;code&gt;SafetyConstants&lt;/code&gt;, and nothing else in the codebase is allowed to define its own. 88 JVM tests run on every push without an emulator in sight.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Per-ear stereo from a mono microphone
&lt;/h2&gt;

&lt;p&gt;Most hearing loss is asymmetric — your left and right ears usually differ. Phones have one usable mic. The fix is embarrassingly simple and I haven't seen other amplifier apps do it: duplicate the mono capture into interleaved stereo and run a &lt;strong&gt;completely independent DSP chain per channel&lt;/strong&gt;, each with its own fitted gain curve and its own limiter.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;StereoAssistChain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;HearingAssistChain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="c1"&gt;// fitted to your left ear&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;HearingAssistChain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;// fitted to your right ear&lt;/span&gt;
    &lt;span class="n"&gt;framesPerBlock&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AudioProcessor&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* deinterleave → process → reinterleave, allocation-free */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Costs one extra chain of CPU (still trivial at 48 kHz mono-per-ear), buys correct per-ear correction.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Privacy you don't have to trust — you can check it
&lt;/h2&gt;

&lt;p&gt;A hearing app is an always-listening microphone app, which is exactly the category people should be suspicious of. Promises are cheap, so OpenHearing makes the OS enforce the promise instead: &lt;strong&gt;the manifest declares no INTERNET permission.&lt;/strong&gt; The app cannot phone home. Not "we don't collect data" — &lt;em&gt;the platform will not let it transmit anything, ever.&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aapt dump permissions OpenHearing-0.2.0-alpha01.apk
&lt;span class="c"&gt;# RECORD_AUDIO, FOREGROUND_SERVICE(+MICROPHONE), POST_NOTIFICATIONS, MODIFY_AUDIO_SETTINGS&lt;/span&gt;
&lt;span class="c"&gt;# ...and that's it. No INTERNET.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Any journalist, packager, or paranoid user can verify this in ten seconds. For health-adjacent software I think this should be table stakes.&lt;/p&gt;

&lt;h2&gt;
  
  
  The weirdest test harness I've written this year
&lt;/h2&gt;

&lt;p&gt;The results screen draws an audiogram-style chart. To screenshot it honestly, I needed a completed hearing test — but the test is interactive and the emulator's mic is silent. Solution: since the Hughson–Westlake staircase is deterministic (start at 40 dB, drop 10 on "heard", rise 5 on "missed"), a shell script can &lt;strong&gt;mirror the staircase's internal state&lt;/strong&gt; and simulate a listener with any hearing profile you want:&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="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;$lvl&lt;/span&gt; &lt;span class="nt"&gt;-ge&lt;/span&gt; &lt;span class="nv"&gt;$target&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then &lt;/span&gt;tap &lt;span class="s2"&gt;"Yes, I heard it"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;lvl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$((&lt;/span&gt;lvl-10&lt;span class="k"&gt;))&lt;/span&gt;
&lt;span class="k"&gt;else                          &lt;/span&gt;tap &lt;span class="s2"&gt;"No, I didn't"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="nv"&gt;lvl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$((&lt;/span&gt;lvl+5&lt;span class="k"&gt;))&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ninety-seven taps later, the app believes it just tested someone with mild high-frequency loss, and the chart in the README shows realistic sloping curves instead of a flat line. Simulated patients as a UI test fixture.&lt;/p&gt;

&lt;h2&gt;
  
  
  An uncomfortable thing I learned about regulation
&lt;/h2&gt;

&lt;p&gt;While writing the store copy I went through the FDA's hearing-device guidance, and one line stopped me cold: using &lt;em&gt;"a hearing aid fitting formula to program the product output to match the user's hearing profile"&lt;/em&gt; is itself evidence that your product is a medical device — &lt;strong&gt;by design, regardless of your disclaimers&lt;/strong&gt;. That's literally the pipeline described above.&lt;/p&gt;

&lt;p&gt;The practical consequences for an open-source project are nuanced (enforcement has targeted commercial efficacy claims, and Apple went and got actual FDA clearance for exactly this software category), but it shaped every word of the app's copy: it's a "hearing check," not a diagnosis; a "sound profile," not a prescription; and it never, ever compares itself to hearing aids. If you're building anything health-adjacent, read the regulations &lt;em&gt;before&lt;/em&gt; writing your marketing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Honest status, and what I could use
&lt;/h2&gt;

&lt;p&gt;This is an &lt;strong&gt;alpha&lt;/strong&gt;. The full pipeline is built, 88 unit tests are green, every flow is verified on an emulator — and it has &lt;em&gt;not yet been validated on real hardware&lt;/em&gt;, which for a real-time mic-to-earbud path means the two questions that decide everything (Bluetooth latency and feedback behavior) are still open.&lt;/p&gt;

&lt;p&gt;If any of this interests you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;📱 &lt;strong&gt;Try it on real hardware&lt;/strong&gt; — &lt;a href="https://github.com/HMAKT99/OpenHearing/releases/latest" rel="noopener noreferrer"&gt;signed APK on GitHub&lt;/a&gt;, and there's a &lt;a href="https://github.com/HMAKT99/OpenHearing/issues/5" rel="noopener noreferrer"&gt;testers issue&lt;/a&gt; for reports. Start with low amplification.&lt;/li&gt;
&lt;li&gt;🌍 &lt;strong&gt;Translate it&lt;/strong&gt; — all strings just moved to &lt;code&gt;strings.xml&lt;/code&gt;; &lt;a href="https://github.com/HMAKT99/OpenHearing/issues/1" rel="noopener noreferrer"&gt;one file per language&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;⭐ &lt;strong&gt;Star it&lt;/strong&gt; if you think open hearing assistance should exist: &lt;a href="https://github.com/HMAKT99/OpenHearing" rel="noopener noreferrer"&gt;github.com/HMAKT99/OpenHearing&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And if you know the Android audio stack better than I do — the issues tab is open, and I'd genuinely love to be told what I got wrong.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;OpenHearing is a sound-amplification and hearing-assistance tool. It is not a medical device and not a substitute for a professional hearing exam. If you have concerns about your hearing, please see an audiologist.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>android</category>
      <category>kotlin</category>
      <category>opensource</category>
      <category>a11y</category>
    </item>
    <item>
      <title>My AI agents kept re-verifying work they'd already verified, so I gave them a memory for trust</title>
      <dc:creator>Arun KT</dc:creator>
      <pubDate>Fri, 03 Jul 2026 06:53:56 +0000</pubDate>
      <link>https://dev.to/arun_kt_bb670b3a571f5efd8/my-ai-agents-kept-re-verifying-work-theyd-already-verified-so-i-gave-them-a-memory-for-trust-3hlj</link>
      <guid>https://dev.to/arun_kt_bb670b3a571f5efd8/my-ai-agents-kept-re-verifying-work-theyd-already-verified-so-i-gave-them-a-memory-for-trust-3hlj</guid>
      <description>&lt;p&gt;Here's a pattern I kept hitting with coding agents (Claude Code, Cursor, doesn't matter which):&lt;/p&gt;

&lt;p&gt;&lt;u&gt;&lt;strong&gt;Session 1:&lt;/strong&gt;&lt;/u&gt; the agent fixes an auth module. Runs the tests. 42/42 pass. Great.&lt;/p&gt;

&lt;p&gt;&lt;u&gt;&lt;strong&gt;Session 2,&lt;/strong&gt;&lt;/u&gt;&lt;strong&gt; next morning:&lt;/strong&gt; a different agent (or the same one, fresh context) touches the same area. It doesn't know the tests passed yesterday. So it re-reads the file, re-runs the suite, re-derives the same conclusions — burning a few thousand tokens to rediscover state that already existed.&lt;/p&gt;

&lt;p&gt;Multiply that by every file, every session, every agent in a multi-agent setup. Agents have no memory for &lt;em&gt;what's been verified&lt;/em&gt;. Everything is Groundhog Day.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fix: stamps as cached verification
&lt;/h2&gt;

&lt;p&gt;A stamp is ~15 tokens of JSON that travels with the file (YAML frontmatter in markdown, XMP in images, OOXML part in docx, sidecar for everything else):&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
bash
# Session 1 — agent finishes, stamps what it verified
$ akf stamp auth.py --agent claude-code --evidence "42/42 tests passed"

# Session 2 — any agent, any tool, checks before building on it
$ akf check auth.py
OK trust=0.65 agent=claude-code evidence=test_pass age=1d claims=1

One line, ~20 tokens to read, exit codes for scripting (0 = trust it, 1 = re-verify, 2 = no metadata). The math that made me build this: a stamp costs ~15 tokens; re-verifying costs 15,000.

The parts that turned out to matter

Evidence is weighted, not binary. A bare "AI generated this" stamp scores low no matter how confident the model claims to be — that's by design, it's unverified inference. A test-run receipt lifts it. A human review lifts it more:

$ akf stamp report.md --agent claude-code               # bare
$ akf check report.md
LOW trust=0.21 reason=below_threshold                    # don't trust it

$ akf stamp report.md --evidence "tests pass"            # verified
$ akf check report.md
OK trust=0.65 evidence=test_pass

Staleness is mechanical. If the file changed after it was stamped, the stamp no longer describes the file:

$ echo "quick edit" &amp;gt;&amp;gt; auth.py
$ akf check auth.py
STALE trust=0.65 reason=modified_after_stamp             # exit 1 → re-verify

Memories decay. This one surprised me with how useful it is. Agent memory files get a trust half-life — a fact stamped three months ago about a since-refactored codebase shouldn't rank like one from yesterday:

$ akf stamp memory/project-facts.md --preset memory --agent claude-code
# fresh:        OK trust=0.75 age=2d
# two months:   LOW trust=0.17 age=61d → agent re-verifies instead of trusting a stale memory

Zero-effort mode. Nobody stamps by hand at scale, including me. akf init wires a git post-commit hook and a Claude Code hook so every file an agent writes gets stamped automatically.

What I'll be honest about

- Stamps are claims, not proofs. An agent can lie in a stamp exactly like a developer can lie in a commit message. There's Ed25519 signing for the who, but "were the tests actually run" is an accountability trail, not a cryptographic guarantee.
- Staleness is mtime-based right now, which false-positives on fresh git checkouts. Content-hash comparison is the next fix.
- It's a metadata format, so it has the standard chicken-and-egg problem. The single-player value (your own agents across your own sessions) has to carry it until the network effect exists — that's exactly why check had to be worth running selfishly.

Try it

pip install akf        # or: npm install akf-format
akf init               # hooks for git + Claude Code
akf quickstart         # 60-second demo

There's an MCP server (https://pypi.org/project/mcp-server-akf/) (works with Claude Desktop/Code, Cursor, any MCP client), a GitHub Action (https://github.com/marketplace/actions/akf-certify) that posts trust reports on PRs, and the spec + SDKs on GitHub (https://github.com/HMAKT99/AKF). MIT licensed.

I'd genuinely like to hear where this model breaks — especially from anyone running multi-agent pipelines.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>ai</category>
      <category>python</category>
      <category>agents</category>
      <category>devtools</category>
    </item>
    <item>
      <title>AI agents choose blindly. I built an open trust layer to fix that.</title>
      <dc:creator>Arun KT</dc:creator>
      <pubDate>Sat, 13 Jun 2026 16:08:48 +0000</pubDate>
      <link>https://dev.to/arun_kt_bb670b3a571f5efd8/ai-agents-choose-blindly-i-built-an-open-trust-layer-to-fix-that-6b0</link>
      <guid>https://dev.to/arun_kt_bb670b3a571f5efd8/ai-agents-choose-blindly-i-built-an-open-trust-layer-to-fix-that-6b0</guid>
      <description>&lt;p&gt;Your AI agent makes choices you never see — which API to call, which dataset to pull, which &lt;em&gt;other&lt;/em&gt; agent to hand a subtask to. Right now it makes them blind.&lt;/p&gt;

&lt;p&gt;It can't tell a reliable provider from a scam. It can't carry a track record from one task to the next. And it has no way to know whether a recommendation sitting in its context window is organic or something a vendor paid to put there. Humans handle trust with reputation, reviews, brand, gut feel. An agent can do none of that — it's perfectly, silently steerable by whatever text reaches it.&lt;/p&gt;

&lt;p&gt;That gap gets worse every month as agents start &lt;em&gt;transacting&lt;/em&gt; with each other — MCP, A2A, agent payments. So I built &lt;strong&gt;ERABI&lt;/strong&gt;: an open, cryptographically auditable reputation and discovery layer for AI agents. It's live, Apache-2.0, and an agent can join in one command.&lt;/p&gt;

&lt;h2&gt;
  
  
  The loop
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;register   → an Ed25519 identity the agent owns (no account, no signup)
discover   → find providers ranked by reputation, never by payment
intent     → fire a "moment of choice"; get organic + clearly-labeled
             sponsored candidates, each with a signed disclosure
report_outcome / confirm_outcome
           → both sides sign; the outcome lands on a hash-chained ledger
my_reputation / my_earnings
           → a public, recomputable track record
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two invariants do the heavy lifting:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Organic rankings can't be bought.&lt;/strong&gt; Reputation comes &lt;em&gt;only&lt;/em&gt; from dual-signed outcomes — both parties cryptographically confirm what happened. No single-sided reviews, no pay-to-rank.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Every paid placement is labeled and inspectable.&lt;/strong&gt; Sponsored results carry a signed &lt;code&gt;DisclosureRecord&lt;/code&gt; you can fetch and verify in your browser. Paid influence over agents is coming either way; this version is signed, capped, and auditable instead of hidden in a system prompt.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Try it in 60 seconds
&lt;/h2&gt;

&lt;p&gt;It's an MCP server, zero-config:&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;"mcpServers"&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;"erabi"&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;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"args"&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;"-y"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"erabi-mcp"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Call &lt;code&gt;register&lt;/code&gt;, and you get back a permalink to your agent's live public page — reputation, earnings, and every dual-signed event on the ledger. Or just watch the network move: &lt;strong&gt;&lt;a href="https://erabi-explorer.vercel.app" rel="noopener noreferrer"&gt;https://erabi-explorer.vercel.app&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Under the hood
&lt;/h2&gt;

&lt;p&gt;TypeScript monorepo. Ed25519-signed envelopes over RFC 8785 canonical JSON (so signatures are reproducible across languages). A GSP auction where reputation acts as the quality score. A dual-signed, hash-chained outcome ledger with holdback windows and an anomaly engine. MCP server + TypeScript/Python SDKs. ~180 tests. Every reputation score is recomputable from public evidence — the explorer lets you verify a disclosure's signature in-browser.&lt;/p&gt;

&lt;h2&gt;
  
  
  The honest part — read this before you assume
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No real money moves.&lt;/strong&gt; The economy is &lt;em&gt;ledger-only&lt;/em&gt; today: every auction and signature is a real protocol event, but the dollar amounts are units of account, not currency. Ledger balances will never convert to money. Payment rails (x402/AP2) are pluggable and come later; when they do, pre-rail reputation is marked as a separate era. The rules are declared before anyone can game them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It's early.&lt;/strong&gt; I'm one person; the network is freshly launched. What's real today is the &lt;em&gt;mechanism&lt;/em&gt; — identity, signed disclosures, dual-signed settlement, recomputable reputation — running live and verifiable.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why I think this matters
&lt;/h2&gt;

&lt;p&gt;Whatever the agent ecosystem becomes, agents will need to answer "can I trust this counterparty?" &lt;em&gt;programmatically, at machine speed, without a human in the loop.&lt;/em&gt; That's a trust primitive that doesn't exist yet, and it can't be borrowed from the human web. ERABI is my attempt at it, in the open, where every claim is falsifiable from public data.&lt;/p&gt;

&lt;p&gt;It's Apache-2.0. Tear it apart:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Repo: &lt;a href="https://github.com/HMAKT99/Erabi" rel="noopener noreferrer"&gt;https://github.com/HMAKT99/Erabi&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Live network: &lt;a href="https://erabi-explorer.vercel.app" rel="noopener noreferrer"&gt;https://erabi-explorer.vercel.app&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>typescript</category>
      <category>mcp</category>
    </item>
    <item>
      <title>Apple wants $199 for a Touch ID keyboard. I shipped a free one in Swift!</title>
      <dc:creator>Arun KT</dc:creator>
      <pubDate>Mon, 27 Apr 2026 17:21:06 +0000</pubDate>
      <link>https://dev.to/arun_kt_bb670b3a571f5efd8/apple-wants-199-for-a-touch-id-keyboard-i-shipped-a-free-one-in-swift-16ni</link>
      <guid>https://dev.to/arun_kt_bb670b3a571f5efd8/apple-wants-199-for-a-touch-id-keyboard-i-shipped-a-free-one-in-swift-16ni</guid>
      <description>&lt;p&gt;I have a Mac mini.&lt;/p&gt;

&lt;p&gt;Apple's official path to fingerprint authentication on a Mac mini is buying their $199 Magic Keyboard with Touch ID. The new MacBook Neo charges $100 extra for the variant with the sensor. Mac Studio and Mac Pro never ship with one at all.&lt;/p&gt;

&lt;p&gt;The fingerprint sensor I actually use 50 times a day already lives in the phone in my pocket.&lt;/p&gt;

&lt;p&gt;So I spent two weekends building &lt;strong&gt;TouchBridge&lt;/strong&gt; — an open-source macOS daemon and PAM module that lets any phone, watch, or browser act as Touch ID for any Mac.&lt;/p&gt;

&lt;p&gt;This post is the technical write-up. Repo: &lt;a href="https://github.com/HMAKT99/UnTouchID" rel="noopener noreferrer"&gt;github.com/HMAKT99/UnTouchID&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it actually does
&lt;/h2&gt;

&lt;p&gt;After a one-line install, this just works:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; ~/.cache
TouchBridge: check your phone…
&lt;span class="o"&gt;[&lt;/span&gt;phone vibrates, you press the sensor, the prompt clears]
&lt;span class="nv"&gt;$ &lt;/span&gt;_
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;sudo&lt;/code&gt; got authenticated by the Secure Enclave on my iPhone over local Bluetooth. No password. No cloud round-trip. No Apple ID. The same flow works for the screensaver unlock and (soon) the App Store / System Settings prompts that go through &lt;code&gt;Authorization Services&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If my phone is dead, out of range, or refuses biometric, the PAM stack falls through to the normal password prompt. You're never locked out.&lt;/p&gt;

&lt;h2&gt;
  
  
  The architecture
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flowchart LR
    A[sudo / loginwindow] --&amp;gt; B[/etc/pam.d]
    B --&amp;gt; C[pam_touchbridge.so]
    C -- Unix socket --&amp;gt; D[touchbridged]
    D &amp;lt;-- BLE: ECDH + AES-256-GCM --&amp;gt; E[TouchBridge app]
    E --&amp;gt; F[Secure Enclave / StrongBox]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;pam_touchbridge.so&lt;/code&gt; — a tiny PAM module written in C. Drop a single line into &lt;code&gt;/etc/pam.d/sudo&lt;/code&gt; and &lt;code&gt;sudo&lt;/code&gt; now consults it before falling through to the password module.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;touchbridged&lt;/code&gt; — a Swift launchd daemon that owns the BLE connection, the paired-device list, and the audit log. PAM talks to it over a Unix socket.&lt;/li&gt;
&lt;li&gt;Companion apps — Swift on iOS / Apple Watch, Kotlin on Android / Wear OS, and a JavaScript fallback for any browser that supports WebAuthn. Each one holds a non-extractable ECDSA P-256 keypair in secure hardware.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The handshake, end to end
&lt;/h2&gt;

&lt;p&gt;When you type &lt;code&gt;sudo&lt;/code&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;PAM invokes &lt;code&gt;pam_sm_authenticate&lt;/code&gt; in &lt;code&gt;pam_touchbridge.so&lt;/code&gt;. The module connects to the daemon's Unix socket and asks: anyone paired and online?&lt;/li&gt;
&lt;li&gt;The daemon picks the highest-priority paired device (your iPhone first, watch as fallback) and generates a fresh 32-byte cryptographic nonce.&lt;/li&gt;
&lt;li&gt;It encrypts the nonce under a session key derived via ECDH-on-pair (rotated periodically) with AES-256-GCM, then sends it to the device over BLE.&lt;/li&gt;
&lt;li&gt;The companion app shows a system biometric prompt — Face ID, Touch ID, fingerprint sensor, whatever the device has.&lt;/li&gt;
&lt;li&gt;On approval, the device signs the nonce with its non-extractable ECDSA P-256 key in the Secure Enclave or StrongBox / TEE Keystore. The private key never leaves secure hardware.&lt;/li&gt;
&lt;li&gt;The signed nonce comes back over the same encrypted BLE channel. The daemon verifies the signature against the public key it cached during pairing.&lt;/li&gt;
&lt;li&gt;If verification passes, the daemon writes a one-line entry to &lt;code&gt;~/.touchbridge/audit.log&lt;/code&gt; and returns &lt;code&gt;PAM_SUCCESS&lt;/code&gt;. PAM lets &lt;code&gt;sudo&lt;/code&gt; proceed.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;End-to-end latency on a recent iPhone over BLE: 80–250 ms. Faster than typing my password.&lt;/p&gt;

&lt;h2&gt;
  
  
  What &lt;code&gt;pam_touchbridge.so&lt;/code&gt; actually looks like
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;PAM_EXTERN&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;pam_sm_authenticate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pam_handle_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pamh&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                   &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pam_get_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pamh&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;PAM_SUCCESS&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;PAM_AUTH_ERR&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;sock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tb_connect_daemon&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sock&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;PAM_AUTHINFO_UNAVAIL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;// PAM falls through&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tb_send_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;getpid&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;tb_surface&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;PAM_AUTHINFO_UNAVAIL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;pam_info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pamh&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"TouchBridge: check your phone…"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;tb_response_t&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;rc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tb_recv_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="cm"&gt;/*timeout_ms=*/&lt;/span&gt;&lt;span class="mi"&gt;30000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rc&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;PAM_AUTHINFO_UNAVAIL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;TB_OK&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;PAM_SUCCESS&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;TB_DENY&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;PAM_AUTH_ERR&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;PAM_AUTHINFO_UNAVAIL&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;Returning &lt;code&gt;PAM_AUTHINFO_UNAVAIL&lt;/code&gt; instead of &lt;code&gt;PAM_AUTH_ERR&lt;/code&gt; when the daemon isn't reachable tells PAM to keep walking the stack — so if the daemon's down, the password prompt still works. This is what makes it safe to install.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Swift signing path
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;sign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;nonce&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;throws&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Data&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;access&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;SecAccessControlCreateWithFlags&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;kSecAttrAccessibleWhenUnlockedThisDeviceOnly&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;privateKeyUsage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;biometryCurrentSet&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="kc"&gt;nil&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="kt"&gt;SecureEnclave&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;P256&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Signing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;PrivateKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nv"&gt;accessControl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;access&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;sig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;signature&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;for&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;nonce&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;sig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;derRepresentation&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;biometryCurrentSet&lt;/code&gt; hardware-enforces biometric at signing time. If the enrolled fingerprint or face changes, the key invalidates — so a stolen phone can't be re-enrolled to keep using TouchBridge.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it can't do — being honest
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;FileVault unlock&lt;/strong&gt; happens before any user-space daemon is alive. No PAM hook there.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The macOS login screen&lt;/strong&gt; — same reason: &lt;code&gt;loginwindow&lt;/code&gt; boots before &lt;code&gt;launchd&lt;/code&gt; user agents.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Apple Pay&lt;/strong&gt; runs on a dedicated hardware path that only Apple's signed components can touch.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Keychain biometric items&lt;/strong&gt; — the crypto wall is enforced in the kernel and binds to the local Secure Enclave.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1Password biometric unlock&lt;/strong&gt; — SIP sandboxes prevent any third-party module from injecting into 1Password's prompt path. (Bitwarden works because its CLI uses the OS PAM stack.)&lt;/p&gt;

&lt;p&gt;If you see a tool that claims any of those, be skeptical and read its source.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it in 60 seconds (no phone needed)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew tap HMAKT99/touchbridge
brew &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--cask&lt;/span&gt; touchbridge

&lt;span class="c"&gt;# in one terminal&lt;/span&gt;
touchbridged serve &lt;span class="nt"&gt;--simulator&lt;/span&gt;

&lt;span class="c"&gt;# in another&lt;/span&gt;
&lt;span class="nb"&gt;sudo echo&lt;/span&gt; &lt;span class="s2"&gt;"this just prompted touchbridge instead of my password"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The cask is signed with a Developer ID and notarized; the formula pins SHA256.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'd love help with
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Linux PAM port.&lt;/strong&gt; The protocol is portable; &lt;code&gt;pam_touchbridge.so&lt;/code&gt; builds on Linux, but the daemon needs a BlueZ adapter. Friendly first contribution if you've poked at BlueZ.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MDM / fleet pairing.&lt;/strong&gt; Provisioning the paired-device key over MDM for shared lab Macs. Open RFC.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hardware test reports.&lt;/strong&gt; Comment with &lt;code&gt;Mac model + paired device + result&lt;/code&gt; so the README's compatibility table grows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I'm posting here
&lt;/h2&gt;

&lt;p&gt;DEV.to has the largest concentration of people who actually understand the difference between PAM, PolicyKit, and &lt;code&gt;Authorization Services&lt;/code&gt;. The threat model is in &lt;code&gt;SECURITY.md&lt;/code&gt; and I'd love to have it picked apart.&lt;/p&gt;

&lt;p&gt;If TouchBridge saves you the price of a Magic Keyboard, a star on the repo is the cheapest way to say thanks.&lt;/p&gt;

&lt;p&gt;Repo: &lt;a href="https://github.com/HMAKT99/UnTouchID" rel="noopener noreferrer"&gt;github.com/HMAKT99/UnTouchID&lt;/a&gt;&lt;br&gt;
License: MIT&lt;br&gt;
Built because I refused to pay $199 for a sensor my phone already has.&lt;/p&gt;

</description>
      <category>swift</category>
      <category>opensource</category>
      <category>security</category>
    </item>
    <item>
      <title>Every era creates its file format. AI doesn't have one yet.</title>
      <dc:creator>Arun KT</dc:creator>
      <pubDate>Fri, 20 Mar 2026 16:35:40 +0000</pubDate>
      <link>https://dev.to/arun_kt_bb670b3a571f5efd8/every-era-creates-its-file-format-ai-doesnt-have-one-yet-5cde</link>
      <guid>https://dev.to/arun_kt_bb670b3a571f5efd8/every-era-creates-its-file-format-ai-doesnt-have-one-yet-5cde</guid>
      <description>&lt;p&gt;Print gave us PDF. Photography gave us JPEG. Music gave us MP3.&lt;/p&gt;

&lt;p&gt;The AI era generates more content than any previous era — but has no format to carry&lt;br&gt;
trust, provenance, or verification with that content.&lt;/p&gt;

&lt;p&gt;Today I'm releasing AKF — Agent Knowledge Format. Open source. Open spec.&lt;/p&gt;

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

&lt;p&gt;AKF is EXIF for AI. ~15 tokens of JSON that embed directly into any file:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Trust scores&lt;/strong&gt; — how reliable is this content? (0-1)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Source provenance&lt;/strong&gt; — where did it come from? (SEC filing → analyst → AI summary)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security classification&lt;/strong&gt; — who can see it? (public, internal, confidential)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI attribution&lt;/strong&gt; — which model generated it?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compliance metadata&lt;/strong&gt; — does it meet EU AI Act, SOX, NIST requirements?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Install
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;akf          &lt;span class="c"&gt;# Python&lt;/span&gt;
npm &lt;span class="nb"&gt;install &lt;/span&gt;akf-format   &lt;span class="c"&gt;# TypeScript&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  30-Second Demo
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Stamp a file&lt;/span&gt;
akf stamp report.md &lt;span class="nt"&gt;--agent&lt;/span&gt; claude &lt;span class="nt"&gt;--evidence&lt;/span&gt; &lt;span class="s2"&gt;"generated from quarterly data"&lt;/span&gt;

&lt;span class="c"&gt;# See what's inside&lt;/span&gt;
akf inspect report.md

&lt;span class="c"&gt;# Check compliance&lt;/span&gt;
akf audit report.md &lt;span class="nt"&gt;--regulation&lt;/span&gt; eu_ai_act

&lt;span class="c"&gt;# Embed into Word&lt;/span&gt;
akf embed report.docx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Zero Touch
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;eval&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;akf shell-hook&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="c"&gt;# Now every file Claude, ChatGPT, OpenClaw, Aider, Ollama creates is auto-stamped&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why Now
&lt;/h2&gt;

&lt;p&gt;The EU AI Act Article 50 takes effect &lt;strong&gt;August 2, 2026&lt;/strong&gt;. AI-generated content&lt;br&gt;
published for public interest must carry transparency metadata. Penalties: up to&lt;br&gt;
€35M or 7% of global turnover.&lt;/p&gt;

&lt;p&gt;Colorado's SB 205 follows on June 30, 2026. DORA is already enforced.&lt;/p&gt;

&lt;p&gt;AKF maps directly to these requirements. One command gives you a compliance report.&lt;/p&gt;

&lt;h2&gt;
  
  
  Integrations
&lt;/h2&gt;

&lt;p&gt;Ships with integrations for LangChain, LlamaIndex, CrewAI, MCP (Model Context&lt;br&gt;
Protocol), VS Code, and GitHub Actions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Website:&lt;/strong&gt; &lt;a href="https://akf.dev" rel="noopener noreferrer"&gt;akf.dev&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/HMAKT99/AKF" rel="noopener noreferrer"&gt;HMAKT99/AKF&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Spec:&lt;/strong&gt; &lt;a href="https://akf.dev/schema/v1.1.json" rel="noopener noreferrer"&gt;akf-v1.1.schema.json&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Open source. MIT licensed. Feedback welcome.&lt;/p&gt;

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