<?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: Andrew David</title>
    <description>The latest articles on DEV Community by Andrew David (@emperorsixpacks).</description>
    <link>https://dev.to/emperorsixpacks</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%2F1015723%2F18ab138e-cadc-43e1-9cf1-546c4e3dd6a2.jpeg</url>
      <title>DEV Community: Andrew David</title>
      <link>https://dev.to/emperorsixpacks</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/emperorsixpacks"/>
    <language>en</language>
    <item>
      <title>Poltergeist: I made a browser extension that haunts the page you're reading</title>
      <dc:creator>Andrew David</dc:creator>
      <pubDate>Sat, 31 Oct 2026 23:38:41 +0000</pubDate>
      <link>https://dev.to/emperorsixpacks/poltergeist-i-made-a-browser-extension-that-haunts-the-page-youre-reading-3lj3</link>
      <guid>https://dev.to/emperorsixpacks/poltergeist-i-made-a-browser-extension-that-haunts-the-page-youre-reading-3lj3</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week4-2026-10-26"&gt;Hacktoberfest Open-Source AI Challenge Week 4: Ghost in the Machine&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/emperorsixpacks/poltergeist/releases" class="crayons-btn crayons-btn--primary" rel="noopener noreferrer"&gt;Grab the extension and haunt a page&lt;/a&gt;
&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Poltergeist&lt;/strong&gt; is a Chrome Manifest V3 extension that literally haunts whatever web page you are reading.&lt;/p&gt;

&lt;p&gt;Most AI browser extensions behave like polite corporate sidebars: you highlight text, click a button, and read a summary in a neat little drawer. &lt;strong&gt;Poltergeist does the exact opposite.&lt;/strong&gt; It treats your browser as a physical, haunted environment.&lt;/p&gt;

&lt;p&gt;When you click &lt;strong&gt;Possess this page&lt;/strong&gt;, a purple-glowing ghost materializes directly over your screen. It reads the page's title, headings, and visible text, then whispers an eerie, hilarious, context-aware observation about &lt;em&gt;that exact page&lt;/em&gt; in a floating speech bubble — spoken aloud with an authentic spectral voice while its mouth animates.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8nvwtkhv8vnfh6gf0vnh.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%2F8nvwtkhv8vnfh6gf0vnh.png" alt="Poltergeist mascot — a purple-glowing ghost" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The Poltergeist mascot: a purple-glowing ghost that materializes over any page you haunt.&lt;/em&gt;&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Features &amp;amp; Capabilities
&lt;/h3&gt;

&lt;p&gt;Poltergeist doesn't stop at a single whisper. It comes packed with a full suite of mischievous interactions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;👻 &lt;strong&gt;Possess&lt;/strong&gt;: Scans the page text (excluding sensitive inputs) and speaks an eerie, hyper-specific whisper with real-time typewriter text and an animated talking mouth.&lt;/li&gt;
&lt;li&gt;🎃 &lt;strong&gt;Trick or Treat&lt;/strong&gt;: An interactive Halloween button powered by a candy economy:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Treats&lt;/strong&gt;: Awards candy points into a glowing HUD, speaks eerie compliments (&lt;em&gt;"This page is positively boo-tiful"&lt;/em&gt;), or delivers creepy fun facts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tricks&lt;/strong&gt;:&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Spooky Headline Mutation&lt;/strong&gt;: Dynamically rewrites the page's headings into chilling alternatives with a glowing orange aesthetic (&lt;code&gt;.pg-spooked&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Screen Flicker&lt;/strong&gt;: Glitches the entire webpage body via CSS hue-rotation and vibration (&lt;code&gt;html.pg-flicker body&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flashlight Mode&lt;/strong&gt;: Plunges the entire webpage into pitch darkness, revealing only a circular spotlight beam that dynamically tracks your mouse cursor (&lt;code&gt;html.pg-dim::before&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cursor Follower&lt;/strong&gt;: Spawns a mini ghost that lerps smoothly behind your cursor, flipping horizontally based on movement direction.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;🎯 &lt;strong&gt;Ghost Hunt&lt;/strong&gt;: An interactive mini-game. The open-weight model picks 5 words from the page text to hide in. Mini ghosts are embedded directly into the text at &lt;code&gt;opacity: .12&lt;/code&gt; (barely visible). A 30-second countdown timer starts in the HUD. You can hover to reveal them or click the &lt;strong&gt;Hint&lt;/strong&gt; button to pulse an uncaught ghost. Catching a ghost triggers a poof vanish animation (&lt;code&gt;pg-vanish&lt;/code&gt;), a voiced taunt, and +1 candy reward!&lt;/li&gt;
&lt;li&gt;✝️ &lt;strong&gt;Exorcise&lt;/strong&gt;: Absolute, clean reversibility. One click restores every mutated headline back to its original text (via &lt;code&gt;WeakMap&lt;/code&gt;), unwraps all ghost hunt spans back to plain text nodes, removes HTML effect classes, silences audio, and unmounts the Shadow DOM root.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;📺 &lt;strong&gt;Watch the Full Video Walkthrough&lt;/strong&gt;: &lt;a href="https://youtu.be/hetrSxxsRDk" rel="noopener noreferrer"&gt;YouTube Demo&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;📁 &lt;strong&gt;Repository Video&lt;/strong&gt;: &lt;a href="//./poltergeist-demo.mp4"&gt;&lt;code&gt;poltergeist-demo.mp4&lt;/code&gt;&lt;/a&gt; (1080p 60fps walkthrough showcasing popup activation, possession, typewriter speech, headline mutation, flicker, flashlight mode, cursor follower, ghost hunt, and clean exorcism).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Visual Walkthrough
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Summoning the Ghost (Popup UI)
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fb3tqmxwm4akpgfgv568z.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%2Fb3tqmxwm4akpgfgv568z.png" alt="Poltergeist Extension Popup" width="800" height="450"&gt;&lt;/a&gt;nsion Popup](&lt;a href="https://raw.githubusercontent.com/emperorsixpacks/poltergeist/main/screenshots/02-popup.png" rel="noopener noreferrer"&gt;https://raw.githubusercontent.com/emperorsixpacks/poltergeist/main/screenshots/02-popup.png&lt;/a&gt;)&lt;br&gt;
&lt;em&gt;Clicking the extension icon opens the 280px popup with our dark design system, glowing SVG mascot, and one-click 'Possess this page' trigger.&lt;/em&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  2. The Haunting: Contextual Whisper &amp;amp; Typewriter Animation
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fuiy1v5z420gel96fvpuz.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%2Fuiy1v5z420gel96fvpuz.png" alt="Possess and Speech Bubble" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The ghost manifests inside an isolated Shadow DOM host (&lt;code&gt;#poltergeist-root&lt;/code&gt;), typing out an in-character observation while its mouth animates in sync with ElevenLabs speech.&lt;/em&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  3. Trick or Treat: Spooky Headline Mutations &amp;amp; Screen Flick
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fl5wdpexnhxvgn0lhtqgt.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%2Fl5wdpexnhxvgn0lhtqgt.png" alt="Headline Mutation" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Real page headings mutate into eerie alternatives with glowing orange text (&lt;code&gt;.pg-spooked&lt;/code&gt;), while the page glitches via CSS animations.&lt;/em&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  4. Flashlight Mode: Dynamic Spotlight Tracking
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fefbbiq9tc1n3pcv4467c.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%2Fefbbiq9tc1n3pcv4467c.png" alt="Flashlight Spotlight Mode" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The page plunges into darkness with a circular spotlight beam (&lt;code&gt;html.pg-dim::before&lt;/code&gt;) and mini ghost follower lerping behind your cursor.&lt;/em&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  5. Ghost Hunt: Interactive Hiding Game
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fk8k2ex2ijdvic1cyo4ac.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%2Fk8k2ex2ijdvic1cyo4ac.png" alt="Ghost Hunt Mini-Game" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;5 words are wrapped with translucent mini ghosts (&lt;code&gt;opacity: .12&lt;/code&gt;). Hover to spot them, click the 'Hint' button to pulse an uncaught ghost, and catch them before the 30-second timer expires!&lt;/em&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  6. Architecture &amp;amp; Clean Reversibility
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fj4jwfrda3u6gvxd59iz7.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%2Fj4jwfrda3u6gvxd59iz7.png" alt="Poltergeist Architecture" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Exorcise cleanses the DOM completely. Zero API keys in the client, 100% Shadow DOM isolation, and open-weight LLMs on Groq.&lt;/em&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/emperorsixpacks" rel="noopener noreferrer"&gt;
        emperorsixpacks
      &lt;/a&gt; / &lt;a href="https://github.com/emperorsixpacks/poltergeist" rel="noopener noreferrer"&gt;
        poltergeist
      &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;Poltergeist&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;A Chrome Manifest V3 extension that haunts the web page you're reading. Built
for the Hacktoberfest &lt;strong&gt;"Ghost in the Machine"&lt;/strong&gt; challenge. AI text runs on
open-weight &lt;strong&gt;gpt-oss via Groq&lt;/strong&gt;, the voice is &lt;strong&gt;ElevenLabs&lt;/strong&gt;, and both are
proxied through a tiny &lt;strong&gt;Render&lt;/strong&gt; service so users never provide their own keys.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Try it (30 seconds, no installs)&lt;/h2&gt;
&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;Grab &lt;code&gt;poltergeist.zip&lt;/code&gt; from the &lt;a href="https://github.com/emperorsixpacks/poltergeist/releases" rel="noopener noreferrer"&gt;latest release&lt;/a&gt; and unzip it.&lt;/li&gt;
&lt;li&gt;Open &lt;code&gt;chrome://extensions&lt;/code&gt; (or &lt;code&gt;brave://extensions&lt;/code&gt;) → toggle &lt;strong&gt;Developer mode&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Load unpacked&lt;/strong&gt; → select the unzipped &lt;code&gt;poltergeist&lt;/code&gt; folder.&lt;/li&gt;
&lt;li&gt;Open any website → click the Poltergeist icon → &lt;strong&gt;Possess this page&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;No keys, no backend setup — the AI and voice run on the hosted Render proxy.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Features&lt;/h2&gt;
&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Possess&lt;/strong&gt; — extracts the page title, headings and ~1500 chars of visible
body text (form, password and payment fields are skipped), asks the model for a
short spooky whisper about the page, shows it…&lt;/li&gt;
&lt;/ol&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/emperorsixpacks/poltergeist" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h3&gt;
  
  
  Core Repository Highlights
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Zero Build Step / Zero Dependencies&lt;/strong&gt;: Pure vanilla JavaScript, standard CSS3, and native Chrome MV3 APIs. No npm install, no bundler, no framework overhead.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;100% Shadow DOM Isolation&lt;/strong&gt;: All ghost UI elements (&lt;code&gt;.pg-widget&lt;/code&gt;, &lt;code&gt;.pg-bubble&lt;/code&gt;, &lt;code&gt;.pg-hud&lt;/code&gt;, cursor follower) render inside an open Shadow DOM hosted at &lt;code&gt;&amp;lt;div id="poltergeist-root"&amp;gt;&lt;/code&gt;. Host page CSS cannot break the ghost, and ghost CSS cannot leak onto the page.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero External Image Requests&lt;/strong&gt;: All visual assets (&lt;code&gt;GHOST_SVG&lt;/code&gt;, &lt;code&gt;MINI_GHOST_SVG&lt;/code&gt;, &lt;code&gt;CANDY_SVG&lt;/code&gt;, &lt;code&gt;PUMPKIN_SVG&lt;/code&gt;) are stored as inline SVG string constants in &lt;code&gt;assets.js&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;




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

&lt;h3&gt;
  
  
  The AI Brain: Open-Weight gpt-oss-120b via Groq
&lt;/h3&gt;

&lt;p&gt;Poltergeist is powered by &lt;strong&gt;gpt-oss-120b&lt;/strong&gt;, OpenAI's open-weight model, served through &lt;strong&gt;Groq&lt;/strong&gt; for sub-second inference speed.&lt;/p&gt;

&lt;p&gt;The model acts as the ghost's subconscious. Through specialized system prompts, it receives sanitized text extracts and returns structured JSON responses for:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Whispers&lt;/strong&gt;: Short, eerie, funny observations (max 25 words) grounded strictly in the page content.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Headlines&lt;/strong&gt;: Rewriting existing page headings into spooky alternatives while preserving list order.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ghost Hunt Words&lt;/strong&gt;: Selecting 5 distinctive words that literally appear in the page text to serve as hiding spots.
&lt;/li&gt;
&lt;/ol&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart LR
    A["Active Web Page"] --&amp;gt;|"Extracts visible text"| B["content.js"]
    B --&amp;gt;|"chrome.runtime.sendMessage"| C["background.js (Service Worker)"]
    C --&amp;gt;|"POST /api/generate &amp;amp; /api/tts"| D["Render Proxy (Zero-Config)"]
    D --&amp;gt;|"Open-Weight LLM Inference"| E["Groq (gpt-oss-120b)"]
    D --&amp;gt;|"Voice Synthesis"| F["ElevenLabs (Ghost Voice)"]
    D --&amp;gt;|"Audio Bytes + Text"| C
    C --&amp;gt;|"Base64 Audio + Typewriter"| G["Shadow DOM (#poltergeist-root)"]&lt;/code&gt;&lt;/pre&gt;



&lt;h3&gt;
  
  
  System Architecture
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Chrome Extension (Manifest V3)&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Service Worker (&lt;code&gt;background.js&lt;/code&gt;)&lt;/strong&gt;: Coordinates API calls, caches the last generated response per URL (so repeat haunts on the same article are instant), and base64-encodes audio for injection.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Content Script (&lt;code&gt;content.js&lt;/code&gt; + &lt;code&gt;content.css&lt;/code&gt; + &lt;code&gt;assets.js&lt;/code&gt;)&lt;/strong&gt;: Extracts visible DOM text while strictly skipping sensitive elements (&lt;code&gt;INPUT&lt;/code&gt;, &lt;code&gt;TEXTAREA&lt;/code&gt;, &lt;code&gt;SELECT&lt;/code&gt;, password fields, headers, and footers). Mounts the isolated Shadow DOM, coordinates typewriter rendering, animates the ghost's mouth during speech, and manages the undo stack.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Popup (&lt;code&gt;popup.html&lt;/code&gt; / &lt;code&gt;popup.js&lt;/code&gt;)&lt;/strong&gt;: A sleek 280px popover adhering to our custom design system (&lt;code&gt;--pg-bg: #120a20&lt;/code&gt;, &lt;code&gt;--pg-purple: #a855f7&lt;/code&gt;, &lt;code&gt;--pg-orange: #ff8a1f&lt;/code&gt;) with a floating ghost avatar and instant "Possess this page" button.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Backend Proxy on Render (&lt;code&gt;server.js&lt;/code&gt;)&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A tiny, zero-dependency Node.js HTTP service hosted on Render (&lt;code&gt;poltergeist-proxy.onrender.com&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Keeps the Groq and ElevenLabs API keys securely server-side.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero Configuration for Users&lt;/strong&gt;: Anyone loading the extension unpacked in Developer Mode can use it immediately without pasting an API key or signing up for third-party services.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Voice Engine &amp;amp; Accessibility&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Voice generated using ElevenLabs' &lt;code&gt;eleven_multilingual_v2&lt;/code&gt; model with a custom ghost voice ID.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Graceful Fallback&lt;/strong&gt;: If network drops or voice credits expire, Poltergeist automatically falls back to the browser's native &lt;code&gt;window.speechSynthesis&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accessibility&lt;/strong&gt;: Full &lt;code&gt;@media (prefers-reduced-motion: reduce)&lt;/code&gt; compliance automatically disables screen flickering, ghost floating, and cursor followers while keeping static UI fully usable.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Why Does Open Innovation Matter?
&lt;/h2&gt;

&lt;p&gt;Open innovation is the entire reason Poltergeist exists.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Model Sovereignty &amp;amp; Portability&lt;/strong&gt;: The ghost's personality is defined by an open-weight model and a prompt. We originally prototyped Poltergeist using a local Ollama instance running Gemma. When we transitioned to &lt;code&gt;gpt-oss-120b&lt;/code&gt; via Groq for instant cloud latency, we didn't have to rewrite proprietary SDKs or accept vendor lock-in. Open weights let you swap the brain freely.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero-Friction Distribution&lt;/strong&gt;: In closed AI ecosystems, building a browser extension usually means forcing users into subscription paywalls or asking them to paste private API keys into an options page. With open-weight models hosted on open infrastructure like Render, we can distribute a delightful, free tool that works out-of-the-box.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Privacy &amp;amp; Trust&lt;/strong&gt;: Browser extensions have privileged access to what you read. With open architecture, users don't have to trust a black box. The code is completely unbundled and readable in plain JavaScript: anyone can inspect how text is extracted, verify that forms and passwords are never touched, and confirm that only the generated whisper is ever sent to the text-to-speech engine.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Remixability&lt;/strong&gt;: Anyone can fork this repository, swap in Mistral, Llama 3, or DeepSeek, alter the ghost's personality from a Halloween poltergeist into an Elizabethan poet or an 80s cyberpunk hacker, and run it locally or on their own server.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  My Agent Session
&lt;/h2&gt;

&lt;p&gt;This project was built and refined in collaboration with &lt;strong&gt;Antigravity&lt;/strong&gt;, Google DeepMind's advanced coding assistant.&lt;/p&gt;

&lt;p&gt;The agent session helped:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Architect the &lt;strong&gt;Shadow DOM isolation system&lt;/strong&gt; to guarantee that complex CSS animations (&lt;code&gt;@keyframes pg-float&lt;/code&gt;, &lt;code&gt;@keyframes pg-talk&lt;/code&gt;, &lt;code&gt;@keyframes pg-blink&lt;/code&gt;) and design tokens never collide with the host page.&lt;/li&gt;
&lt;li&gt;Implement the &lt;strong&gt;WeakMap reversibility engine&lt;/strong&gt; for headline mutations and text node wrapping during the Ghost Hunt.&lt;/li&gt;
&lt;li&gt;Build the automated &lt;strong&gt;headless browser recording pipeline&lt;/strong&gt; using Playwright, Chromium, and FFmpeg to generate the full-resolution synchronized demo video with real ElevenLabs audio.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Spirit of It
&lt;/h2&gt;

&lt;p&gt;The magic of Poltergeist lands in the unexpected moments.&lt;/p&gt;

&lt;p&gt;When you open a dense, dry technical specification, a Wikipedia article on medieval architecture, or an obscure recipe blog, and press &lt;em&gt;Possess this page&lt;/em&gt;, you don't get a generic canned Halloween sound effect. You hear a raspy, eerie whisper pointing out something absurdly specific from paragraph three that only someone reading along with you would notice.&lt;/p&gt;

&lt;p&gt;It turns passive browsing into an interactive theatrical performance. That is the essence of &lt;strong&gt;"Ghost in the Machine"&lt;/strong&gt;: open-weight AI stepping out of the terminal and making the web feel playful, mysterious, and alive.&lt;/p&gt;




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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of Render&lt;/strong&gt;: Zero-dependency Node.js proxy deployed on Render (&lt;code&gt;poltergeist-proxy&lt;/code&gt;), enabling serverless key management and zero-configuration extension usage.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of Groq&lt;/strong&gt;: Ultra-low-latency inference using open-weight &lt;code&gt;gpt-oss-120b&lt;/code&gt; on Groq, delivering sub-second ghost responses and real-time headline rewrites.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of ElevenLabs&lt;/strong&gt;: Dynamic text-to-speech synthesis using custom voice profiles, synced with SVG mouth animations and fallback speech synthesis.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
    </item>
    <item>
      <title>How to Implement In-Memory Caching in GoLang</title>
      <dc:creator>Andrew David</dc:creator>
      <pubDate>Thu, 27 Nov 2025 13:18:15 +0000</pubDate>
      <link>https://dev.to/emperorsixpacks/how-to-implement-in-memory-caching-in-golang-5fa8</link>
      <guid>https://dev.to/emperorsixpacks/how-to-implement-in-memory-caching-in-golang-5fa8</guid>
      <description>&lt;h2&gt;
  
  
  The Why?
&lt;/h2&gt;

&lt;p&gt;I recently worked on Airtable OAuth authentication for a project and needed a place to store state and challenge code for later request validation. The obvious solution is to use a third-party solution like Redis (Which I am a big fan of), but I wanted to try out in-memory caching. Yes, I reviewed other tools like MemeCache, but am I not an engineer?&lt;/p&gt;

&lt;h2&gt;
  
  
  The What?
&lt;/h2&gt;

&lt;p&gt;When you start your Go app, Python app, or Node app, you can store certain data in the process, making it available throughout the program's lifetime. This data lives in the RAM (Random Access Memory), making it easily accessible by the program whenever it needs it. Most caching systems like Redis also store their data in RAM, but unlike Redis, an in-memory cache is not persistent.&lt;/p&gt;

&lt;p&gt;A simple in-memory cache typically maintains a key-value store in memory, tracks when each item should expire (using TTL — Time to Live), and optionally uses an LRU (Least Recently Used) policy to remove older items when a maximum size is reached. The cache runs in the same process as your application, making reads and writes extremely fast. However, because everything is stored in memory, all data is lost when the application stops.&lt;/p&gt;

&lt;h2&gt;
  
  
  Less Talk, more code !!!
&lt;/h2&gt;

&lt;p&gt;Before we code, let’s go over a few things I think you should know&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;LRU (Least Recently Used)&lt;/strong&gt; → My phone has a bunch of apps that I do not use—apps that have been on my phone for the longest time, occupying good space. LRU is an eviction policy that removes the least-used item in a cache. Essentially, think of it as removing that app you haven’t used in months so you can make room for the new game you want to install. Essentially, you are removing the oldest unused item, regardless of whether it has been accessed a lot in the past.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;LFU (Least Frequently Used)&lt;/strong&gt; → Imagine this: your bag can only hold four books. If you get a new one, you'll need to remove a book to make room, and usually, you'll remove the book you read less. The same thing applies to an in-memory cache. LFU is an eviction policy that ranks items based on how often they’re used, and when space runs out, it removes the least-frequently-used item to make room for new ones.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;TTL (Time To Live)&lt;/strong&gt; → This defines how long we want an item to stay in our cache. It's like setting an expiry date — once the TTL has elapsed, the item is considered stale and no longer valid. Any future attempts to get that item will fail or trigger a refresh. TTL is useful for keeping data fresh and automatically clearing out old or irrelevant entries without needing manual intervention or cleanup.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cache Hit, Cache Miss&lt;/strong&gt; → Whenever we request an item from the cache, a &lt;strong&gt;cache hit&lt;/strong&gt; occurs if the item exists and is still valid. A &lt;strong&gt;cache miss&lt;/strong&gt;, on the other hand, happens when the item is not found or has expired.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;So now we code, right?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Well, not just yet, there are still a few things we need to talk about, sorry :)&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;The Design&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;To build our cache, we’re going to keep things simple with just three components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A map to store the items&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The cache itself&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A Janitor to clean up our mess&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Now we code
&lt;/h3&gt;

&lt;p&gt;Let’s start by defining a very simple struct to hold all the data. After that, I’ll walk you through what each part represents.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Cache Items&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Item&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;value&lt;/span&gt;    &lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="n"&gt;duration&lt;/span&gt; &lt;span class="kt"&gt;int64&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// Main cache struct&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;items&lt;/span&gt;   &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="n"&gt;Item&lt;/span&gt;
    &lt;span class="n"&gt;mu&lt;/span&gt;      &lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RWMutex&lt;/span&gt;
    &lt;span class="n"&gt;janitor&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Janitor&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// handles clean up&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Janitor&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;interval&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Duration&lt;/span&gt;
    &lt;span class="n"&gt;stop&lt;/span&gt;     &lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;Item&lt;/code&gt; struct contains two fields: &lt;code&gt;Value&lt;/code&gt; and &lt;code&gt;Duration&lt;/code&gt;. Normally, you might use &lt;code&gt;time.Time&lt;/code&gt; for expiration, but here, &lt;code&gt;Duration&lt;/code&gt; is stored as an integer timestamp—a design choice to keep things simple and flexible.&lt;/p&gt;

&lt;p&gt;As for the &lt;code&gt;Cache&lt;/code&gt; struct, you might notice that it's unexported (made private). This allows us to expose a global constructor to create the cache instance. The real reason behind this design, though, is that I implemented it using the &lt;strong&gt;singleton pattern&lt;/strong&gt;—meaning I wanted to ensure that only one instance of the cache exists throughout the entire program.&lt;/p&gt;

&lt;p&gt;One thing I may have forgotten to mention is that our cache needs to be &lt;strong&gt;thread-safe&lt;/strong&gt;. This means it should prevent &lt;strong&gt;race conditions&lt;/strong&gt;, where two processes or goroutines try to modify the state of the cache at the same time.&lt;/p&gt;

&lt;p&gt;Go provides a solution for this through the use of a &lt;strong&gt;mutex&lt;/strong&gt;—a locking mechanism that ensures only one thread or goroutine can access a resource at a time. By locking the cache during operations, we prevent data corruption and maintain consistency.&lt;/p&gt;

&lt;p&gt;Another important component is the &lt;strong&gt;Janitor&lt;/strong&gt;. This is a lightweight scheduler that periodically runs in the background to clean up expired items from the cache. It helps free up memory and makes room for newer items, keeping the cache lean and efficient.&lt;/p&gt;

&lt;h3&gt;
  
  
  Expanding Item
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;//Check if Item is expired&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt; &lt;span class="n"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Expired&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;duration&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="m"&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="no"&gt;false&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;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UnixNano&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;duration&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This method returns a &lt;code&gt;bool&lt;/code&gt; indicating whether an item has expired by checking if its timestamp (&lt;code&gt;Duration&lt;/code&gt;, remember) is less than the current time. But before doing that, it first checks if the &lt;code&gt;Duration&lt;/code&gt; is &lt;code&gt;0&lt;/code&gt;. If it is, the method returns &lt;code&gt;false&lt;/code&gt;, meaning the item should not expire.&lt;/p&gt;

&lt;p&gt;This is intentional. Sometimes, you may not want certain items in the cache to ever expire—you want them to persist for as long as the program is running. In this design, any item with a &lt;code&gt;Duration&lt;/code&gt; value of &lt;code&gt;0&lt;/code&gt; is treated as having &lt;strong&gt;no expiration&lt;/strong&gt;, and therefore is never evicted by the cleanup process.&lt;/p&gt;

&lt;h3&gt;
  
  
  Set
&lt;/h3&gt;

&lt;p&gt;Now we can begin working on our cache. The first method we’re going to add is &lt;code&gt;Set&lt;/code&gt;—this allows us to populate the cache with data that we can retrieve and use later.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Store a value in cache with a defined ttl&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="n"&gt;ttl&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RUnLock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="kt"&gt;int64&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ttl&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;ttl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DefaultDuration&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ttl&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ttl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UnixNano&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RLock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;    &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;duration&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;Set&lt;/code&gt; method stores a value in the cache under a specific key, along with an optional TTL (Time To Live). If no TTL is provided, and the &lt;code&gt;DefaultDuration&lt;/code&gt; is &lt;code&gt;0&lt;/code&gt;, the item will be stored &lt;strong&gt;without expiration&lt;/strong&gt;, meaning it will stay in the cache indefinitely unless manually removed.&lt;/p&gt;

&lt;p&gt;If a TTL is provided (i.e. greater than zero), it is converted to a Unix timestamp (&lt;code&gt;int64&lt;/code&gt;) for efficient comparison during retrieval or cleanup.&lt;/p&gt;

&lt;p&gt;Finally, the method locks the cache for writing to ensure thread safety, then inserts the item into the cache map.&lt;/p&gt;

&lt;h3&gt;
  
  
  Let’s do Get, Delete, Len, you get the gist now
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Get an Item from store using its key&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RLock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Expired&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RUnlock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RUnlock&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;item&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// Delete an item from store by its key&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RLock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nb"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RUnlock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// Return the lenght of items in store&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Len&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RLock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RUnlock&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;n&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alright, we’re almost done—I promise. The &lt;code&gt;Get&lt;/code&gt; function retrieves an item from the cache using its key. First, it locks the cache for reading and checks if the key exists in the &lt;code&gt;items&lt;/code&gt; map. If it doesn’t, it returns &lt;code&gt;nil&lt;/code&gt; and &lt;code&gt;false&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If the item does exist, the function checks whether it has expired using the &lt;code&gt;Expired()&lt;/code&gt; method. If it has, it unlocks the cache and returns &lt;code&gt;nil&lt;/code&gt; and &lt;code&gt;false&lt;/code&gt;. Otherwise, it returns the item’s value along with &lt;code&gt;true&lt;/code&gt; to indicate a successful cache hit.&lt;/p&gt;

&lt;p&gt;The next function is &lt;code&gt;Delete&lt;/code&gt;. This function removes an item from the cache by its key. It first locks the cache for reading and checks if the key exists in the &lt;code&gt;items&lt;/code&gt; map. If it doesn’t, it returns &lt;code&gt;false&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If the key exists, it deletes the entry from the map and then unlocks the cache. Finally, it returns &lt;code&gt;true&lt;/code&gt; to indicate that the item was successfully removed.&lt;/p&gt;

&lt;p&gt;And finally &lt;code&gt;Len&lt;/code&gt;. This returns the length of items in the items map; nothing too fancy here.&lt;/p&gt;

&lt;h3&gt;
  
  
  But wait, there is one more thing
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Delete all expired items from store&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;DeleteExpired&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RLock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Expired&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&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="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RUnlock&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;Remember when I mentioned we have a &lt;strong&gt;Janitor&lt;/strong&gt;? The &lt;code&gt;DeleteExpired&lt;/code&gt; function is part of that cleanup process. It loops over all the items in the store and checks whether each one has expired. If an item is expired, it calls the &lt;code&gt;Delete&lt;/code&gt; function to remove it from the cache.&lt;/p&gt;

&lt;p&gt;This helps ensure the cache doesn't keep stale data and frees up memory for new entries, keeping the cache clean.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Janitor
&lt;/h3&gt;

&lt;p&gt;Now let’s talk about how the &lt;strong&gt;Janitor&lt;/strong&gt; runs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Run janitor clean up after intervals&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Janitor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ticker&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewTicker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;interval&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="k"&gt;select&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;ticker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DeleteExpired&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stop&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;ticker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stop&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;Run&lt;/code&gt; method starts a ticker that fires at intervals defined by the user. On each tick, it calls &lt;code&gt;DeleteExpired()&lt;/code&gt; on the cache — this is how we automatically clean up expired items without the user needing to call anything manually.&lt;/p&gt;

&lt;p&gt;We also listen for a stop signal through the &lt;code&gt;stop&lt;/code&gt; channel. Once that signal is received, we stop the ticker and exit the loop.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;stopExceution&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;janitor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stop&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;startJanitor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;interval&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;janitor&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Janitor&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;interval&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;stop&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;     &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;janitor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;janitor&lt;/span&gt;
    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="n"&gt;janitor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&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;There’s also a &lt;code&gt;stopExecution&lt;/code&gt; function that sends the stop signal to the janitor. This gives us a way to &lt;strong&gt;&lt;em&gt;gracefully shut down&lt;/em&gt;&lt;/strong&gt; the cleanup process when the program is closing or we no longer need the cache.&lt;/p&gt;

&lt;p&gt;Finally, the &lt;code&gt;runJanitor&lt;/code&gt; function wires everything together. It creates a new Janitor with a cleanup interval, assigns it to the cache, and runs it in a goroutine so it works in the background.&lt;/p&gt;

&lt;h3&gt;
  
  
  Putting it all together
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;GetCache&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;cache&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="n"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;once&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Do&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;defaultCache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;runJanitor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DefaultCacheInterval&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;defaultCache&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;runtime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetFinalizer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;defaultCache&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stopExceution&lt;/span&gt;&lt;span class="p"&gt;)&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;defaultCache&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can run our cache and see our little in-memory cache in action&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This is a very small and maybe not production-ready cache, but I still remember the excitement I felt when it finally worked—and how it helped me with my little project (which I promise I did not abandon).&lt;/p&gt;

&lt;p&gt;In my next article, we’ll look at how to expand this further by adding &lt;strong&gt;LRU&lt;/strong&gt; support to the cache.&lt;/p&gt;

&lt;p&gt;Now remember: just because you &lt;em&gt;can&lt;/em&gt; build something yourself doesn’t always mean you &lt;em&gt;should&lt;/em&gt;. It’s often a smart move to use existing tools, especially when caching isn’t the core of your project.&lt;/p&gt;

&lt;p&gt;That said... I &lt;em&gt;do&lt;/em&gt; think you should try building your own &lt;a href="https://emperorsixpacks.hashnode.dev/how-to-implement-multi-device-authentication-system-with-fastapi-redis-and-jwt" rel="noopener noreferrer"&gt;multi-auth system&lt;/a&gt; at least once. Until next time ✌🏽&lt;/p&gt;

</description>
      <category>lru</category>
      <category>cache</category>
      <category>programming</category>
      <category>go</category>
    </item>
    <item>
      <title>x402: Pay-Per-Use Internet</title>
      <dc:creator>Andrew David</dc:creator>
      <pubDate>Thu, 27 Nov 2025 13:07:09 +0000</pubDate>
      <link>https://dev.to/emperorsixpacks/x402-pay-per-use-internet-4p30</link>
      <guid>https://dev.to/emperorsixpacks/x402-pay-per-use-internet-4p30</guid>
      <description>&lt;h2&gt;
  
  
  We All Hate Free Trials (Well, I Do)
&lt;/h2&gt;

&lt;p&gt;Sometimes I just want to test something new. Maybe it’s a new AI image tool, a premium API, pay for a digital content to a creator, some data service everyone won’t shut up about. But nope—the first thing I see is “Start your 7-day free trial!” Great… except now I have to hand over my card on day one. Then I spend the whole week stressing that I’ll forget to cancel and get slapped with a $99 charge for something I used only once.&lt;/p&gt;

&lt;p&gt;Even worse: sometimes I want my AI agent (ChatGPT, Claude, Grok) to use that service for me. Which means what—give my card to the AI? I’m reckless, but an AI agent is probably ten times more reckless than me.&lt;/p&gt;

&lt;p&gt;It’s dumb. We shouldn’t need credit cards just to test stuff. With x402, I load a single wallet once—with however much I feel like (even five bucks). From that moment on, me and any AI agent I control can tap into hundreds of services and pay only for what we actually use, down to the penny. No cards floating around. No surprise bills. No “don’t forget to cancel” alarms. I pay for what I use. My agent pays for what it uses. Everyone wins.&lt;/p&gt;

&lt;h2&gt;
  
  
  So what is x402 and Why?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Evolution of Web Payments — and Why x402 Matters
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;402 status code&lt;/strong&gt; has been around since the very beginning of HTTP. The idea was simple: if a resource needs payment before you can access it, the server would return a 402.&lt;/p&gt;

&lt;p&gt;The problem: nobody actually used it.&lt;br&gt;&lt;br&gt;
Not because the idea was bad, but because there was no standard way to &lt;em&gt;pay over HTTP&lt;/em&gt;. So developers defaulted to &lt;strong&gt;403 Unauthorized&lt;/strong&gt;, and everyone just built their own systems—subscriptions, one-time links, prepaid credits.&lt;/p&gt;

&lt;p&gt;These solutions work, but they all live &lt;em&gt;outside&lt;/em&gt; the actual web request. The big unanswered questions were:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;How do we handle &lt;strong&gt;payments inside a request&lt;/strong&gt;?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How do we &lt;strong&gt;send payments over HTTP&lt;/strong&gt;?&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Stablecoins Changed the Game
&lt;/h3&gt;

&lt;p&gt;Then stablecoins blew up. Between 2021 and 2025:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Supply jumped from &lt;strong&gt;under $30B&lt;/strong&gt; to &lt;strong&gt;over $280B&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;On-chain volume hit &lt;strong&gt;$27 trillion&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Governments finally gave clear rules (EU’s MiCA, U.S. GENIUS Act, and similar laws)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Stablecoins basically became the first form of money that’s fast, global, cheap, programmable, and actually works online. Perfect for internet payments.&lt;/p&gt;
&lt;h3&gt;
  
  
  x402: Payments Directly Through HTTP
&lt;/h3&gt;

&lt;p&gt;In May 2025, &lt;strong&gt;Coinbase introduced x402&lt;/strong&gt;, a simple idea that unlocks a lot of possibilities. It revives the old 402 status code and gives it a real purpose.&lt;/p&gt;

&lt;p&gt;With x402, if a resource requires payment, the server can return a &lt;strong&gt;402 Payment Required&lt;/strong&gt; response that includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;how much you need to pay&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;where to send the payment&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;optional details about what you're buying&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The client—your browser, app, or even an AI agent—can then pay instantly on chains like &lt;strong&gt;Solana, Base, or Polygon&lt;/strong&gt;, and the server delivers the requested content &lt;strong&gt;in the same connection&lt;/strong&gt;. No accounts, no signups Just pay-and-go.&lt;/p&gt;
&lt;h3&gt;
  
  
  Perfect Timing for AI Agents
&lt;/h3&gt;

&lt;p&gt;AI agents are exploding in popularity, and they constantly make requests, pull data, call APIs, and use computational resources. With x402:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Agents can &lt;strong&gt;pay for exactly what they use&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;MCP servers can &lt;strong&gt;charge per request&lt;/strong&gt; automatically&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Digital systems can &lt;strong&gt;trade with each other&lt;/strong&gt; without any human setup&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This allows for more robust agentic systems and true agentic commerce&lt;/p&gt;
&lt;h3&gt;
  
  
  Microtransactions Finally Make Sense
&lt;/h3&gt;

&lt;p&gt;One of the best things about x402 is that tiny payments—stuff like a few cents or even fractions of a cent—actually become practical. With credit cards, fees make this impossible. But with fast crypto networks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Pay &lt;strong&gt;1¢&lt;/strong&gt; to read an article&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Pay &lt;strong&gt;per API call&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Pay &lt;strong&gt;by the second&lt;/strong&gt; for compute&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Pay &lt;strong&gt;per kilobyte&lt;/strong&gt; of data&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This means companies can finally drop the free trial and allow test the product without having to worry about remembering to cancel another subscription.&lt;/p&gt;
&lt;h2&gt;
  
  
  So how does It work?
&lt;/h2&gt;

&lt;p&gt;At its core, x402 involves &lt;strong&gt;three main players&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The Seller&lt;/strong&gt; – the server or service hosting the resource you want&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The Buyer&lt;/strong&gt; – you (or your app, agent, or browser)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The Facilitator&lt;/strong&gt; – the service that verifies signatures and settles payments on-chain&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  1. The Buyer
&lt;/h3&gt;

&lt;p&gt;You (the buyer) send a regular GET or POST request to the server, but with one extra header:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;X-Wallet&lt;/code&gt; header, which includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;your wallet address&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;the payment methods/networks your client supports&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This basically tells the server:&lt;br&gt;&lt;br&gt;
&lt;strong&gt;“Hey, I have a wallet. If this costs money, I’m ready.”&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  2. The Seller
&lt;/h3&gt;

&lt;p&gt;If the resource is paywalled, the server returns a &lt;strong&gt;402 Payment Required&lt;/strong&gt; response containing an invoice.&lt;/p&gt;

&lt;p&gt;Example:&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;"maxAmountRequired"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0.01"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/api/video/generate"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Access requires payment"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"payTo"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0xABCDEF1234567390ABCDEF1234567890ABCDEF12"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"asset"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0xA0b86991C6218236c1d19D4a2e9Eb0cE3606EB48"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"network"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"base-mainnet"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This tells the buyer exactly what needs to be paid, in what currency, and where.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Gasless payments using EIP-3008
&lt;/h3&gt;

&lt;p&gt;x402 uses &lt;a href="https://eips.ethereum.org/EIPS/eip-3009" rel="noopener noreferrer"&gt;&lt;strong&gt;EIP-3008: TransferWithAuthorization&lt;/strong&gt;&lt;/a&gt; to enable &lt;em&gt;gasless&lt;/em&gt; transfers.&lt;/p&gt;

&lt;p&gt;Instead of sending a transaction on-chain, the buyer:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Signs a payload authorizing the payment&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Sends that signed payload back to the seller in an &lt;code&gt;X-Payment&lt;/code&gt; header&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Example:&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="err"&gt;X-Payment:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;lt;signed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;EIP&lt;/span&gt;&lt;span class="mi"&gt;-3008&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;payload&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No gas. Just a signature.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. The Seller forwards the signature to the Facilitator
&lt;/h3&gt;

&lt;p&gt;The seller never posts anything directly on-chain.&lt;/p&gt;

&lt;p&gt;Instead, it forwards the signed payment to the facilitator, who:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;verifies it&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;settles the payment&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;confirms everything succeeded&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once payment is settled, the seller returns the requested resource—&lt;strong&gt;all in the same request flow&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Not API Keys?
&lt;/h2&gt;

&lt;p&gt;x420 shines by allowing users to make transactions &lt;strong&gt;without needing API keys&lt;/strong&gt; or even accounts on the services they interact with. This means a single wallet can grant access to premium services across multiple platforms.&lt;/p&gt;

&lt;p&gt;The major advantage is that &lt;strong&gt;AI agents can independently compose and pay for API requests&lt;/strong&gt; without any user intervention. Imagine you have an AI agent that needs to publish posts every day based on what’s trending in the country. Your agent will need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A search tool to find what’s currently trending&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Access to Twitter/X to gather up-to-date news and topics&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The ability to publish a post on your Twitter/X account&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Normally, this requires API credits and API keys for platforms like Google and Twitter. While manageable for a small project, the number of API keys quickly becomes overwhelming as your system grows and you integrate more services.&lt;/p&gt;

&lt;p&gt;With x420, &lt;strong&gt;one wallet covers the cost of all transactions&lt;/strong&gt;, regardless of the number of services involved. All you need to manage is the balance in that single wallet. And you can even set spend limits so your AI agent doese’t spend above a certain threshold.&lt;/p&gt;

&lt;h2&gt;
  
  
  Now The problem
&lt;/h2&gt;

&lt;p&gt;x402 is impressive—&lt;em&gt;really&lt;/em&gt; impressive—but it still carries challenges that are common across the entire crypto ecosystem. The most significant concern is that crypto transactions generally &lt;strong&gt;cannot be traced back to a specific individual or organization&lt;/strong&gt;. While this privacy is a feature, it also creates the potential for x402 to be misused for money laundering or online fraud. These concerns are not unique to x402; they apply broadly to most blockchain-based systems and projects.&lt;/p&gt;

&lt;p&gt;Another important issue currently being worked on is transparency. Even though the origin of an agent’s transaction may be private to the service provider, the &lt;strong&gt;transaction itself is still publicly visible on the blockchain&lt;/strong&gt;. This means that, despite appearing anonymous, your agent’s actions can still be tracked, and most users do not want their agent’s financial activity to be publicly exposed.&lt;/p&gt;

&lt;p&gt;Addressing this would require &lt;a href="https://x.com/PRXVTai/status/1991962982155448347?s=20" rel="noopener noreferrer"&gt;&lt;strong&gt;privacy-preserving transactions&lt;/strong&gt;&lt;/a&gt;, along with &lt;strong&gt;selective disclosure&lt;/strong&gt;—allowing only authorized parties (such as auditors or regulators) to view transaction details when necessary.&lt;/p&gt;

&lt;p&gt;Another concern with x402 is the &lt;strong&gt;lack of chargebacks or refunds&lt;/strong&gt;. Because transactions are irreversible, victims these of scams cannot recover lost funds. This raises the risk of an increase in crypto scams.&lt;/p&gt;

&lt;p&gt;One proposed solution is the introduction of &lt;strong&gt;reputation systems&lt;/strong&gt;. Services can be rated by users and agents, and poor ratings reduce the likelihood that others will trust or interact with them. While this improves accountability, it does not fully solve the chargeback problem, as victims still cannot retrieve their money.&lt;/p&gt;

&lt;h2&gt;
  
  
  The conclusion
&lt;/h2&gt;

&lt;p&gt;So yeah—that’s x402. This article isn’t meant to be highly technical, but it gives you a broad overview of what x402 is and its potential impact on online payments. One user even described it as &lt;em&gt;“the next big thing after sliced bread.”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Innovation around x402 is moving fast, and &lt;strong&gt;version 2 is already on the way&lt;/strong&gt; with even more improvements. One of the most exciting aspects of x402 is that it’s simply a &lt;strong&gt;set of rules for moving money over HTTP&lt;/strong&gt;. Although crypto is currently being used as the payment layer, the standard itself is not limited to crypto. This means x402 has the potential to move even &lt;strong&gt;fiat currency over HTTP&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Experiments have already been conducted using services like Stripe—not yet public, but promising—which shows just how far-reaching the potential of x402 could be. The future of online payments built on this standard is genuinely exciting.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.reuters.com/business/finance/stablecoins-market-cap-surges-record-high-us-senate-passes-bill-2025-06-18/" rel="noopener noreferrer"&gt;Stablecoins' market cap surges to record high as US senate passes bill&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.x402.org/" rel="noopener noreferrer"&gt;x402.org&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://x402.gitbook.io/x402" rel="noopener noreferrer"&gt;https://x402.gitbook.io/x402&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.quicknode.com/guides/infrastructure/how-to-use-x402-payment-required" rel="noopener noreferrer"&gt;How to Implement a Crypto Paywall with x402 Payment Protocol&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://open.spotify.com/episode/40zesAep8MlNYiPBbiXpXX?si=ec267f921de64f23" rel="noopener noreferrer"&gt;How the x402 Standard is Enabling AI Agents to Pay Each Other -Ep. 948&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://open.spotify.com/episode/6QLYIyrCEig3zUfD56twLn?si=b4e9146e67404f75" rel="noopener noreferrer"&gt;x402: The Key to Internet Money, Micropayments &amp;amp; The AI Economy&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=XL_Nn4oep6M&amp;amp;t=23498s" rel="noopener noreferrer"&gt;Devconnect ARG - M2 Yellow Pavilion&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>x402</category>
      <category>ai</category>
      <category>blockchain</category>
      <category>payments</category>
    </item>
  </channel>
</rss>
