Looking for DTMF transceiver module

I’m looking for a DTMF transceiver module compatible with Arduino.
So far I have not located one that uses the MT8880 chip which as a lot of support in the Arduino community. I hope you all can point me in the right direction.

DMARC Is Now a Proper Internet Standard: What Changed in RFC 9989/9990/9991

DMARC has been an Informational RFC since 2015. That changed this month.

RFC 9989 replaces RFC 7489 and elevates DMARC to Standards Track, reflecting over a decade of deployment experience and near-universal adoption across the email ecosystem. The spec was also split into three separate documents:

Splitting them allows each component to evolve independently. Here’s what changed.

The DNS Tree Walk Replaces the Public Suffix List

This is the most significant architectural change.

RFC 7489 used the Public Suffix List to determine organizational domain boundaries. To find the org domain for mail.example.co.uk, you’d look up co.uk in the PSL, then take one label to the left. It works, but the problems are real: external dependency, manual maintenance, potential staleness, no support for non-obvious namespace boundaries.

RFC 9989 introduces the DNS Tree Walk as the alternative. The algorithm walks up the DNS tree looking for _dmarc TXT records, starting from the sending domain and moving toward the root. It caps at eight queries to prevent DoS amplification.

For most domains this changes nothing operationally. For complex organizations with deep subdomain hierarchies, or operators running public suffix domains that want their own DMARC policies, it’s a meaningful improvement.

The new psd tag lets a domain declare itself as a Public Suffix Domain, enabling DMARC policy coverage at that level.

New Tags

t — Test Mode

Replaces the behavioral role of pct. Where pct=0 meant “apply policy to 0% of failing messages,” t=y explicitly signals that the policy is in test mode and shouldn’t be enforced.

The distinction between “policy exists but is being staged” and “policy is active against a subset of traffic” is now unambiguous.

v=DMARC1; p=quarantine; t=y; rua=mailto:[email protected]

np — Non-Existent Subdomain Policy

Allows separate policy handling for subdomains that have no DNS records at all. Previously, sp applied to all subdomains. Now you can distinguish between legitimate configured subdomains (sp) and mail claiming to originate from subdomains that don’t exist in DNS (np).

Non-existent subdomains sending mail are almost always spoofing, so np=reject is often the right default.

psd — Public Suffix Domain

Marks the domain as a Public Suffix Domain for the DNS Tree Walk algorithm.

Removed Tags

pct — Gone

Percentage-based partial enforcement has been removed. Use t=y for test mode instead.

rf — Report Format

Removed. Only AFRF format was ever widely implemented. The tag was vestigial.

ri — Report Interval

Removed. Aggregate reports are daily. The tag existed, receivers rarely honored it, and the spec now reflects reality.

Aggregate Reporting Changes (RFC 9990)

The aggregate reporting spec was extracted from RFC 7489 into its own document. The format remains XML with several refinements.

DKIM selector is now mandatory in reports. Previously optional, it’s required for understanding which DKIM key configuration is producing results — which matters for key rotation debugging.

New discovery method field indicates whether the receiver used psl or treewalk to find the organizational domain. Useful for diagnosing alignment issues during the transition period.

Extension framework allows future XML schema additions within defined namespaces without breaking existing parsers.

The schema changes are backward-compatible. Well-formed RFC 7489 reports will still parse. If you’re running your own DMARC report parser, the new fields are additive.

Failure Reporting Changes (RFC 9991)

The changes here are more significant for implementors.

Identity-Alignment is now a mandatory ARF header. Failure reports must include this field listing which authentication mechanisms failed to produce an aligned pass, or none if all passed. This was absent from the original spec, leading to inconsistent implementations.

Rate limiting is now required. RFC 9991 explicitly mandates that report generators implement rate limits. This closes a known gap: failure reports can be triggered by an attacker sending large volumes of spoofed mail, making an unrated reporting system a DoS amplification vector.

dmarc is now a formal ARF authentication failure type. The Authentication-Failure ARF header now includes dmarc as a valid type value alongside the existing dkim and spf types.

Privacy guidance is significantly expanded. The document adds detailed guidance on PII redaction, URI validation, and secure transport for failure reports. If you’re forwarding RUF reports to a third-party reporting service, the privacy section of RFC 9991 is worth reading before you do.

What You Actually Need to Do

For most domain owners, nothing changes immediately. RFC 9989 is backward-compatible with RFC 7489 and your existing DMARC record continues to work.

The practical checklist:

  • Remove pct tags from your DMARC records. Receiver behavior around deprecated tags will vary as implementations update.
  • If you’re using pct=0 for staged rollouts, move to t=y to signal test mode explicitly.
  • If you’re operating mail infrastructure (MTAs, DMARC reporting tools, monitoring systems), the Identity-Alignment requirement in RFC 9991 and the psd/treewalk changes in RFC 9989 require implementation updates.
  • Public Suffix Domain operators should evaluate adding psd=y once receiver support is established.

The Standards Track designation matters for enterprise and government procurement environments where “Informational RFC” raised compliance questions. DMARC is now a proper internet standard, not a proposal.

OpenTelemetry Is Now a CNCF Graduate — and It’s Coming for Your AI Stack

OpenTelemetry graduated as a CNCF project on May 21, 2026. That’s not just a badge — it’s the formal recognition that OTel has won the observability standards race. But graduation isn’t the finish line. The project is now squarely aimed at the AI infrastructure era, with GenAI semantic conventions already shipping in VS Code Copilot, OpenAI Codex, and Claude Code.

“Graduation is not the finish line. The OpenTelemetry community remains committed to building interoperable, high-quality observability standards and tooling for cloud native software at global scale.”
— OpenTelemetry project blog

What actually changed

  • CNCF graduation — OTel moved from incubating to graduated, joining Kubernetes, Prometheus, and a handful of other foundational cloud-native projects. This signals production-readiness and long-term stewardship.
  • Origins — formed from the merger of OpenTracing and OpenCensus, OTel has absorbed thousands of contributors across language SDKs, semantic conventions, and the Collector.
  • Declarative configuration went stable — a quieter but significant win: you can now configure the OTel Collector declaratively, which matters for GitOps and platform teams managing collectors at scale.
  • GenAI semantic conventions are in active use — the gen_ai.* attribute namespace standardises how LLM operations are recorded: model name, input/output token counts, finish reasons, tool calls, and (when opted in) full prompt/response content.
  • Major AI tools already emit OTel — VS Code Copilot, OpenAI Codex, and Claude Code all export OTel telemetry today. That’s not an aspiration — it’s already the default for the most-used AI coding tools.

Why this matters

OTel is the first observability framework that’s genuinely spanning both cloud-native infrastructure and AI workloads under a single standard. That’s a big deal.

Before the GenAI semantic conventions, monitoring an AI agent meant vendor-specific dashboards, proprietary SDKs, or rolling your own spans. Now you get a common schema — gen_ai.request.model, gen_ai.usage.input_tokens, gen_ai.client.operation.duration — that any OTLP-compatible backend can ingest and visualise.

The practical upside: if your AI agent takes 45 seconds to answer a question, you can now tell whether it was the model, a slow tool call, or a retry loop — without guessing. Token costs, latency histograms, and tool invocation traces all flow through the same pipeline you already run for your services.

The graduation timing is deliberate. OTel is establishing itself as the standard before the AI observability market fragments into proprietary tooling. That’s the same playbook it ran against Prometheus/Jaeger fragmentation in the cloud-native space.

What to do

If you’re building AI-powered apps:

  • Instrument with the GenAI semantic conventions now — they’re in use and under active development, so your feedback shapes what gets standardised.
  • Try the free Aspire Dashboard Docker image for local GenAI telemetry exploration — OTLP-native, no cloud account required.

If you’re a platform/infra engineer:

  • OTel Collector declarative config is now stable — worth revisiting your collector setup if you deferred it waiting for stability.
  • Check if your AI tooling already emits OTel (Copilot and Codex do) — you may have free telemetry sitting uncollected.

If you’re evaluating observability vendors:

  • Prioritise OTLP-native backends. Vendor lock-in via proprietary agents is increasingly a bad bet when the standard is this mature.

Sources: CNCF graduation announcement · OpenTelemetry blog · TNS analysis

✏️ Drafted with KewBot (AI), edited and approved by Drew.

OpenHuman Follows OpenClaw’s Rise, But With an Obsidian Brain

A few nights ago I watched someone demo OpenHuman from a folding table in a cramped apartment kitchen. Their laptop was surrounded by the normal sediment of modern technical life. Two half-drunk energy drinks. Browser tabs stacked into microscopic slivers. Discord notifications firing constantly. A local Ollama instance eating RAM in the background like a starving animal.

The weird part was not the agent itself.

The weird part was how naturally it seemed to inhabit the machine.

Not as a chatbot sitting inside a browser tab waiting politely for prompts. More like a persistent layer hanging around the operating system itself. Watching workflows accumulate. Compressing information. Building continuity from digital residue.

That feeling is why people keep comparing OpenHuman to OpenClaw, even though the projects are aiming at slightly different targets.

OpenClaw helped normalize the idea that desktop AI agents could feel immediate and tactile instead of purely experimental. It brought the whole “local desktop operator” concept out of research demos and into ordinary developer workflows.

OpenHuman follows directly behind it, but the philosophy underneath feels heavier. Less focused on action alone. More interested in persistence, memory architecture, and environmental awareness.

Not just an agent.

An accumulating cognitive system.

That distinction matters more than people realize.

The AI Industry Keeps Rebuilding Goldfish

One of the stranger problems in modern AI is how stateless everything still feels.

You can feed a system thousands of words about your work, habits, projects, tone, and environment, then close the window and watch the entire cognitive state disappear into vapor ten seconds later. Even products advertising “memory” often behave like glorified sticky notes taped onto transient systems.

OpenHuman approaches this differently.

According to the project documentation, it continuously fetches data from connected sources like GitHub, Gmail, calendars, local files, and chats, then compresses and stores them into markdown-based “Memory Trees.”

That little markdown detail changes the entire emotional texture of the project.

Because suddenly this starts sounding less like a chatbot and more like an Obsidian vault that became semi-sentient.

Local markdown.

Persistent memory.

Searchable context structures.

Continuous accumulation.

You can feel the influence of a generation of users who stopped trusting pure cloud abstraction and started organizing their cognition locally instead. Researchers. developers. obsessive note hoarders with twenty thousand interconnected documents sitting inside graph view.

OpenHuman understands something important:

People are not actually craving “AI.”

They are craving continuity.

They want systems that remember the shape of their digital life without forcing them to reconstruct context manually every morning.

That is the same instinct that helped OpenClaw spread so quickly.

Reduce friction between intention and execution.

Reduce friction between memory and workflow.

Reduce friction between human thought and machine state.

The 20 Minute Loop Changes Everything

One of the smartest design choices in OpenHuman is also one of the easiest to overlook.

The auto-fetch loop.

Every twenty minutes, the system can pull fresh information from connected sources and integrate it into its local memory structures.

That sounds small until you think about how fragmented modern cognition actually is.

Your life is not organized into neat prompts.

It leaks everywhere.

Terminal history. unfinished commits. screenshots. tabs you meant to read three days ago. Discord messages. bug reports. grocery reminders. PDFs opened at 2am and forgotten instantly afterward.

Most AI systems still force users to manually curate relevance.

OpenHuman instead tries to aggressively harvest context before you even ask for anything.

That changes the relationship entirely.

The agent starts feeling less like software you “use” and more like an informational organism quietly living beside your workflow.

And unlike a lot of AI marketing language right now, the project does not really pretend otherwise. The README openly describes connecting accounts and letting the system continuously fetch local context.

There is something refreshing about that honesty.

No mystical AGI theater.

Just infrastructure.

Memory compression.

Environmental awareness.

Accumulation.

OpenHuman Feels More Like an Operating Layer Than an Assistant

A lot of AI products still optimize for demos.

OpenHuman feels optimized for inhabitation.

That difference becomes obvious once you start looking at the tooling stack built directly into the project.

Filesystem access.

Git operations.

Web search.

Voice support.

Linting.

Testing.

Model routing.

Local inference integration through Ollama.

The average AI workflow in 2026 has become weirdly exhausting. Developers are juggling five subscriptions, multiple vector databases, disconnected memory layers, browser agents, shell agents, local models, remote APIs, and enough .env variables to qualify as emotional warfare.

Then one dependency updates overnight and the entire stack implodes.

OpenHuman is clearly trying to collapse that fragmentation into a single continuously running environment.

And honestly, that may be more important than benchmark performance.

The AI industry keeps treating models as products.

Increasingly, models are becoming infrastructure instead.

The real differentiator is the environment surrounding them.

The Model Routing Philosophy Is Quietly Smart

One of the more mature aspects of OpenHuman is how casually it treats model orchestration.

The system supports routing different tasks to different models depending on workload and capability. Lightweight tasks can use faster cheaper models. More reasoning-intensive tasks can escalate upward. Local inference can coexist with cloud inference.

That sounds technical and boring until you realize how important the philosophical shift actually is.

Most consumer AI products still pretend there is one singular intelligence behind the curtain.

But the future increasingly looks modular.

Different systems for different cognitive loads.

Fast pattern matching.

Slow reasoning.

Vision interpretation.

Background compression.

Tool execution.

Memory synthesis.

OpenHuman treats model selection as infrastructure rather than spectacle.

That is the correct direction.

The routing layer disappears into workflow instead of becoming part of the performance.

It feels closer to an operating system than a chatbot.

And weirdly enough, closer to how human cognition already functions.

TokenJuice Sounds Fake But It Solves a Real Problem

The funniest thing in the entire project might be the name “TokenJuice.”

It sounds like something invented during a sleep deprivation episode at 4:17am.

But the underlying idea is actually important.

Before information reaches the LLM, OpenHuman preprocesses and compresses it. HTML becomes markdown. unnecessary formatting gets stripped. URLs get shortened. noisy payloads get reduced.

This matters because token inefficiency is becoming one of the defining problems of agent systems.

A shocking amount of AI infrastructure right now basically functions like shipping companies transporting garbage across expensive context windows.

Massive bloated HTML payloads.

Duplicated formatting.

Navigation elements.

Unnecessary markup.

Dead weight everywhere.

OpenHuman appears unusually aware of this problem.

The project claims TokenJuice can reduce token usage dramatically, sometimes up to 80% depending on the workload.

Whether those exact numbers hold consistently across large-scale deployment is still unclear. The project remains early beta and moving quickly. But the architectural instinct is absolutely correct.

The next generation of AI systems probably will not win through sheer model size alone.

They will win through context efficiency.

Memory engineering.

Compression quality.

Retrieval precision.

The surrounding ecosystem matters more every month.

Local First Is Becoming Emotional Infrastructure

One reason OpenHuman resonates so strongly with developers right now has nothing to do with AI capability itself.

It is locality.

The software stores data locally. Uses SQLite persistence. Organizes information into markdown structures compatible with tools people already trust. Supports local inference through Ollama.

That changes the emotional relationship between user and machine.

Cloud-native software increasingly feels rented. Temporary. Subscription-shaped.

You do not fully inhabit those systems.

You borrow them.

Local-first software feels different.

You experiment more freely.

You build stranger workflows.

You stop worrying quite as much about whether the company maintaining the platform will pivot into nonsense six months later.

There is a reason older technical communities became emotionally attached to desktop software. The machine itself felt like territory.

OpenHuman taps into some of that feeling again.

Not nostalgically.

Functionally.

The Rough Edges Are Part of Why People Care

One thing I appreciate about OpenHuman is that it still feels unfinished in visible ways.

Not polished into corporate smoothness.

The README openly describes the project as early beta.

That honesty matters because the current AI ecosystem has become saturated with highly polished unreality. Beautiful launch videos covering fragile systems held together by API glue and investor optimism.

OpenHuman instead feels like an ambitious desktop project from an earlier era of computing.

Slightly unstable.

Deeply opinionated.

Built by people who clearly use the thing themselves.

Even the mascot interface contributes to that atmosphere a little. Not in an overdesigned corporate way. More like software created by developers who still think computers are supposed to feel personal.

Underneath all of that sits the actual important shift:

persistent contextual memory.

That is the real story here.

Not the mascot.

Not the agent hype.

Memory architecture.

OpenHuman Reveals Where Desktop AI Is Heading

I do not think projects like OpenHuman are important because they represent finished products.

They matter because they expose trajectory.

The first wave of consumer AI treated intelligence itself as the product. Bigger models. smarter responses. increasingly theatrical reasoning demos.

The next wave appears far more interested in continuity.

Persistent memory.

Environmental awareness.

Context accumulation.

Long-term workflow integration.

Artificial familiarity.

And honestly, that may reshape daily computing faster than AGI ever does.

Because most people do not need a godlike intelligence living inside their laptop.

They need a system that remembers where they left things.

A system that understands continuity between fragments.

A system that can exist beside their actual life instead of resetting every session like a concussed intern.

That is the feeling OpenHuman is chasing.

Not pure intelligence.

Residency.

The machine remaining there long enough to develop informational gravity.

And if OpenClaw helped normalize the idea that local desktop agents could act, OpenHuman may end up normalizing the idea that they can remember too.

Further Reading

If you’re experimenting with OpenHuman locally and want something more practical than endless GitHub issue archaeology, The Desktop Operator’s Guide to OpenHuman: Local Inference, Model Routing, and Stable Deployment is one of the better deployment-focused breakdowns floating around right now. It stays grounded in actual workflow setup instead of drifting into generic AI futurism.

OpenHuman GitHub README

OpenHuman Repository

Build a Live Flight Radar in a Single HTML File

One HTML file. No npm, no frameworks, no backend. Open it in a browser and watch live aircraft move across an interactive map.

We’ll use Leaflet.js for the map and a free aviation API for real-time ADS-B positions. The whole thing is under 100 lines of code, and the planes update every 30 seconds.

What We’re Building

An interactive radar-style map that:

  • Shows live aircraft positions over any region you choose
  • Rotates plane icons to match actual heading
  • Color-codes planes by altitude (green → yellow → red)
  • Displays flight number, route, speed and altitude on click
  • Auto-refreshes every 30 seconds without reloading the page

Before You Start

Grab a free API key from AirLabs — takes 30 seconds, no credit card. Their free tier returns real-time lat/lng, heading, altitude, speed, and route data, which is everything we need for a map.

The Full Code

I’ll show the complete file first, then walk through how it works. Create a file called radar.html, paste this in, replace YOUR_API_KEY, and open it in your browser:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Live Flight Radar</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css">
<script src="https://unpkg.com/[email protected]/dist/leaflet.js"></script>
<style>
  * { margin: 0; padding: 0; box-sizing: border-box; }
  body { background: #0a0a1a; font-family: monospace; }
  #map { width: 100vw; height: 100vh; }
  #hud {
    position: fixed; top: 16px; left: 16px; z-index: 999;
    background: rgba(10,10,26,0.85); color: #8cf;
    padding: 10px 16px; border-radius: 8px;
    font-size: 13px; pointer-events: none;
    border: 1px solid rgba(100,180,255,0.2);
  }
  #hud b { color: #fff; }
</style>
</head>
<body>
<div id="hud">
  Flights: <b id="count">—</b> &nbsp;|&nbsp;
  Updated: <b id="time">—</b> &nbsp;|&nbsp;
  Next refresh: <b id="tick">30</b>s
</div>
<div id="map"></div>

<script>
const API_KEY = "YOUR_API_KEY";
const BBOX    = [44, 2, 52, 20];      // Central Europe — change to your region
const REFRESH = 30;                    // seconds between updates

// --- MAP SETUP ---
const map = L.map("map", {
  center: [(BBOX[0]+BBOX[2])/2, (BBOX[1]+BBOX[3])/2],
  zoom: 6,
  zoomControl: false
});

L.tileLayer("https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png", {
  attribution: '&copy; OpenStreetMap &copy; CARTO',
  maxZoom: 18
}).addTo(map);

L.control.zoom({ position: "bottomright" }).addTo(map);

// --- PLANE ICON FACTORY ---
function planeIcon(dir, alt) {
  let color;
  if (alt == null)    color = "#888";
  else if (alt < 3000) color = "#2ecc71";
  else if (alt < 8000) color = "#f1c40f";
  else                 color = "#e74c3c";

  return L.divIcon({
    className: "",
    iconSize: [22, 22],
    iconAnchor: [11, 11],
    html: `<div style="
      font-size:18px; color:${color};
      transform:rotate(${dir || 0}deg);
      text-shadow:0 0 4px ${color}44;
      line-height:22px; text-align:center;
    ">✈</div>`
  });
}

// --- POPUP ---
function popupHTML(f) {
  const flight = f.flight_iata || f.hex || "—";
  const route  = `${f.dep_iata || "?"} → ${f.arr_iata || "?"}`;
  const altFt  = f.alt ? Math.round(f.alt * 3.281).toLocaleString() : "—";
  const kts    = f.speed ? Math.round(f.speed * 0.54) : "—";
  return `<div style="font-family:monospace;font-size:13px;min-width:150px">
    <b style="font-size:15px">${flight}</b><br>
    ${route}<br>
    ✈ ${f.aircraft_icao || "—"}<br>
    ↑ ${altFt} ft &nbsp; → ${kts} kts
  </div>`;
}

// --- STATE ---
let markers = [];

async function fetchFlights() {
  const url = `https://airlabs.co/api/v9/flights`
    + `?api_key=${API_KEY}`
    + `&bbox=${BBOX.join(",")}`
    + `&_fields=hex,flag,lat,lng,dir,alt,speed,flight_iata,dep_iata,arr_iata,aircraft_icao`;

  try {
    const res = await fetch(url);
    const json = await res.json();
    const flights = json.response || [];

    // clear old markers
    markers.forEach(m => map.removeLayer(m));
    markers = [];

    flights.forEach(f => {
      if (!f.lat || !f.lng) return;
      const m = L.marker([f.lat, f.lng], {
        icon: planeIcon(f.dir, f.alt)
      }).bindPopup(popupHTML(f));
      m.addTo(map);
      markers.push(m);
    });

    // update HUD
    document.getElementById("count").textContent = flights.length;
    document.getElementById("time").textContent =
      new Date().toLocaleTimeString();
  } catch (err) {
    console.error("Fetch failed:", err);
  }
}

// --- REFRESH LOOP ---
let countdown = REFRESH;

fetchFlights();  // first load

setInterval(() => {
  countdown--;
  document.getElementById("tick").textContent = countdown;
  if (countdown <= 0) {
    countdown = REFRESH;
    fetchFlights();
  }
}, 1000);
</script>
</body>
</html>

That’s the entire thing. Let’s break it down.

How It Works

The Map

We initialize Leaflet with CARTO’s dark basemap — it gives that clean radar aesthetic, and it’s free. The map centers automatically on whatever bounding box you configure.

const BBOX = [44, 2, 52, 20]; // south-lat, west-lng, north-lat, east-lng

Change this to any region you want:

  • USA (lower 48): [24, -125, 50, -66]
  • Southeast Asia: [-10, 95, 25, 145]
  • UK + Ireland: [49, -11, 60, 2]
  • Middle East: [12, 32, 42, 62]
  • Your city: grab coordinates from Google Maps, add ±2 degrees

The API Call

One fetch() to the AirLabs /flights endpoint with a bounding box filter:

const url = `https://airlabs.co/api/v9/flights`
  + `?api_key=${API_KEY}`
  + `&bbox=${BBOX.join(",")}`
  + `&_fields=hex,flag,lat,lng,dir,alt,speed,flight_iata,dep_iata,arr_iata,aircraft_icao`;

The _fieldsparameter limits the response to only what we need — keeps it fast. A typical European bounding box returns 500–1500 flights depending on time of day.

Plane Icons

Each plane is a Leaflet DivIcon — a rotated ✈ character. The dir field from the API gives heading in degrees, so we apply a CSS rotate() transform. Color is based on altitude:

Altitude Color Meaning
< 3,000m 🟢 Green Climbing or descending
3,000–8,000m 🟡 Yellow Mid-altitude
> 8,000m 🔴 Red Cruising altitude

Auto-Refresh

A simple setIntervalcounts down from 30 seconds. When it hits zero, it calls fetchFlights() again — clears old markers, fetches new positions, plots them. The HUD in the top-left shows the flight count, last update time, and countdown to next refresh.

No WebSockets, no server, no state management. Just clear and redraw.

Customization Ideas

Filter by airline — add &airline_iata=UA to the URL to show only United Airlines flights. Great for monitoring a specific carrier.

Departure board — swap /flights for /schedules?dep_iata=JFK to build a live airport departure board. Returns gate, terminal, delay, and status.

Draw flight paths — when user clicks a plane, fetch the route with /routes?dep_iata=${dep}&arr_iata=${arr} and draw a great-circle arc between the airports using Leaflet’s polyline.

Add airports — fetch /airports?_fields=iata_code,name,lat,lng and plot them as circles on the map. Now your radar has reference points.

Mobile PWA — wrap this HTML in a simple service worker and add a manifest. You’ve got a progressive web app that works offline (minus the live data) and installs on your home screen.

Deployment

This is a single HTML file with zero dependencies (Leaflet loads from CDN). You can:

  • GitHub Pages — push radar.html as index.html, enable Pages, done
  • Netlify / Vercel — drag and drop the file
  • Literally any web server — it’s static HTML

One caveat: the API key is visible in client-side code. For a personal project or portfolio demo, this is fine — just use the free tier key and don’t worry about it. For production, proxy the request through a small serverless function (Cloudflare Workers or Vercel Edge work great for this).

The entire project is 93 lines of HTML/CSS/JS. No build step, no node_modules, no dependencies to update. Just a file that shows you where every plane in the sky is, right now.

DuckDB 1.5.3 Adds Quack Client-Server, SQLite Gets Cypher Graph Extension

DuckDB 1.5.3 Adds Quack Client-Server, SQLite Gets Cypher Graph Extension

Today’s Highlights

This week, DuckDB releases version 1.5.3 with the Quack client-server protocol, enabling concurrent writes for the embedded analytics database. Additionally, the GraphQLite extension brings powerful Cypher-based graph database capabilities directly to SQLite users.

DuckDB 1.5.3: Not an Ordinary Patch Release (DuckDB Blog)

Source: https://duckdb.org/2026/05/20/announcing-duckdb-153.html

DuckDB 1.5.3, despite its “patch release” designation, delivers a substantial update to the popular in-process analytical database. The headline feature is the integration of Quack as a core extension, which fundamentally changes how DuckDB can be deployed. Quack introduces a robust client-server protocol, allowing multiple concurrent writers to interact with a single DuckDB instance. This transforms DuckDB from a purely embedded, single-process database into a more flexible system capable of handling shared data access in distributed environments, while retaining its lightweight, high-performance characteristics.

Beyond Quack, the 1.5.3 release includes numerous other enhancements through its rich extension ecosystem. These likely involve expanded support for various data formats, improved query optimization, and potentially new functions or connectors that bolster DuckDB’s role in data ingestion and transformation workflows. For developers and data engineers, this means a more powerful and adaptable tool for in-process analytics, especially for scenarios requiring fast, local data processing or the creation of portable data applications. The continued evolution of DuckDB’s extension framework, coupled with core performance improvements, reinforces its growing importance in the modern data stack for both interactive analysis and robust data pipeline components. The ability to manage concurrent writes via Quack is a game-changer for shared data access patterns.

Comment: Quack’s promotion to a core extension is huge; it makes DuckDB viable for shared workloads beyond pure embedded analytics, blurring the lines with traditional client-server databases while keeping its speed.

Quack: The DuckDB Client-Server Protocol (DuckDB Blog)

Source: https://duckdb.org/2026/05/12/quack-remote-protocol.html

This blog post introduces Quack, DuckDB’s new client-server protocol, marking a significant evolution for the embedded analytical database. Quack enables multiple DuckDB instances to communicate and share data, effectively allowing a client-server setup. This is a crucial development for use cases where concurrent access and shared state are required, moving beyond DuckDB’s traditional single-process, embedded model. The protocol is designed with simplicity and DuckDB’s performance philosophy in mind, ensuring minimal overhead.

The Quack protocol specifically addresses the need for shared data environments without sacrificing the lightweight nature of DuckDB. It facilitates scenarios where data needs to be accessed and modified by multiple applications or users simultaneously, which was previously a challenge for DuckDB’s embedded architecture. The announcement emphasizes Quack’s simple design, aiming to integrate seamlessly into existing workflows while providing robust capabilities for remote interaction and concurrent writes. This innovation significantly broadens the application scope for DuckDB, making it suitable for more complex data architectures where a scalable, yet agile, analytical database solution is needed. It showcases DuckDB’s commitment to evolving beyond a purely in-process tool while maintaining its core strengths.

Comment: Quack’s approach to client-server for DuckDB is pragmatic; it opens up entirely new use cases for collaboration and shared data without requiring a heavy external server infrastructure.

GraphQLite: An SQLite Extension for Graph Database Capabilities (r/database)

Source: https://reddit.com/r/Database/comments/1tkdqut/need_a_lightweight_graph_visualizer_for/

The news item highlights GraphQLite, an innovative SQLite extension that imbues the popular embedded database with graph database functionalities. By integrating the Cypher query language, GraphQLite allows users to perform complex graph traversals and manipulations directly within their SQLite databases. This development is particularly significant for developers who require lightweight, embedded solutions with advanced data relationship modeling capabilities, without the overhead of a dedicated graph database system.

GraphQLite transforms SQLite into a powerful tool for managing interconnected data, making it suitable for applications like social networks, recommendation engines, or knowledge graphs that benefit from graph-native queries. The ability to use Cypher, a widely recognized graph query language, lowers the barrier to entry for developers familiar with graph databases. This extension exemplifies the versatility of SQLite’s architecture, demonstrating how it can be extended to support specialized data models and query paradigms. For the SQLite ecosystem, GraphQLite represents a crucial step towards expanding its utility beyond traditional relational data, catering to modern data challenges that demand more flexible and expressive data structures.

Comment: An SQLite extension offering full graph database capabilities via Cypher is a game-changer for embedded applications needing complex relationship querying; it brings powerful analytical patterns to the edge.

Custom Copilot Agents: Building Domain-Expert AI Teammates with Skills, MCP Tools, and Custom Knowledge

Most Teams Are Still Using 5% of Copilot

Most developers still treat GitHub Copilot like a very good autocomplete engine. That’s useful, but it’s not the real unlock.

The interesting shift happens when Copilot stops acting like a generic assistant and starts acting like a domain-expert teammate. Instead of re-explaining your deployment rules, your content pipeline, or your release checklist every session, you package that expertise once. Then Copilot shows up already knowing the job.

That’s the difference between using Copilot and building with Copilot. One gives you better suggestions. The other gives you reusable specialists that understand your repo, your patterns, and your operating model.

Want the complete agent manifest, copilot-instructions.md, YAML skill files, and MCP integration code? It’s all in Newsletter Issue #11 → subscribe here

What I Mean by a Custom Copilot Agent

At a high level, a custom Copilot agent is a packaged specialization layer for GitHub Copilot. It gives Copilot a clear identity, focused instructions, and the right tools for a specific domain.

GitHub’s customization story already points in this direction. You can customize Copilot for your project, add knowledge bases, and connect MCP servers to Copilot CLI. I think of a custom agent as the point where those ideas converge into one opinionated package.

The Model Context Protocol gives Copilot a standard way to reach external systems and tools. Your agent design decides which tools matter, which context belongs in memory, and which workflows are worth encoding.

The 3-Layer Architecture

The easiest way to think about custom agent architecture is as three layers working together:

  1. Agent profile layer — the identity declaration.
    This is the small config surface that says: this Copilot specialist owns this domain, responds to these triggers, and should load this knowledge. In practice, that’s an agent manifest in an .agent.md file, often paired with copilot-instructions.md when the runtime needs repository-wide guidance.

  2. Skills layer — the structured prompts.
    This is where repeatable expertise lives. A skill isn’t vague guidance. It’s a reusable procedure: what to check, what to avoid, what sequence to follow, and what “done” looks like. I’ve written before about this in Agent Skills: Microsoft Just Shipped What You’ve Been Building.

  3. Tools layer — the execution boundary.
    This is where the agent gets hands. MCP lets Copilot reach beyond text and interact with real systems. That might mean GitHub workflows, a video pipeline, internal APIs, or a governed task system.

If you’ve read The Three Layers Your AI Agent Is Missing, this should feel familiar. The point is separation of concerns. The agent profile says who the specialist is. Skills say how it should behave. Tools define what it can actually do.

Newsletter subscribers get the full 3-layer custom agent architecture with real TypeScript, configs, and production patterns.

In Issue #11 I share the actual implementation details: the agent manifest pattern, the copilot-instructions.md setup, the YAML skill layout, and the MCP integration shape I use to turn Copilot into domain-specific teammates instead of generic chat sessions.

Two Production Examples

Here are two real patterns from production that made this click for me.

1. A DevOps Copilot Specialist

One custom agent pattern I keep coming back to is a DevOps-focused Copilot specialist.

The domain is narrow but deep: release prep, workflow governance, branch rules, dependency checks, and CI visibility. The agent profile establishes the role, the skills encode the repeatable procedures, and the tools expose the right capabilities to inspect workflows and surface the next action.

That means I don’t start every session with “here are our branch rules, here is how we label releases, here is what counts as a blocker.” Copilot starts there already.

2. A Vidpipe Media Workflow Specialist

The second example is from my media pipeline.

A video workflow has a lot of hidden knowledge: ingestion steps, transcript expectations, caption rules, retry paths, and publishing handoffs.

A custom agent turns that operational knowledge into a reusable asset. The skills explain the workflow stages, the tools expose pipeline state, and the agent profile keeps the agent locked into the right role.

And those two custom agents are only the teaser. The third production pattern in Issue #11 is the meta one: a custom agent that helps me scaffold more custom agents faster.

When to Build a Custom Agent vs. Use Skills Directly

Not every recurring workflow needs a full custom agent.

If the problem is mostly procedural, start with skills. Skills are the cheapest leverage point. They let you capture repeatable know-how without adding a new identity surface or tool boundary.

Build a full custom agent when all three signals show up:

  • you keep repeating the same domain context in session after session
  • the domain needs its own toolset, not just better instructions
  • the work benefits from a clear specialist identity instead of a generic assistant persona

My rule of thumb is simple: if Copilot only needs a better playbook, write a skill. If Copilot needs a job title, a toolkit, and a memory of how your team works, build a custom agent.

That line matters because agent sprawl is real. A skill library can stay lightweight. A custom agent should earn its existence.

Where the Deep Dive Lives

This article is deliberately the overview.

The full agent manifest, copilot-instructions.md, YAML examples, and TypeScript MCP integration is in Issue #11. That’s where I walk through the actual layering, show the production examples in more detail, and explain why this architecture compounds once you have more than one specialist running.

If this topic connects with the rest of your platform work, the next stop after the newsletter is The Agentic Development Blueprint. It connects custom agent architecture to the bigger system: context engineering, guardrails, workflows, and governance.

You should also read the surrounding pieces if you want the bigger picture:

The Bottom Line

The teams getting the biggest lift from Copilot are not the ones asking better one-off questions. They’re the ones turning Copilot into reusable specialists that understand their actual environment.

This was the overview. Newsletter Issue #11 has the step-by-step implementation with real files from 3 production custom agents → Subscribe at htek.dev/newsletter

RTX 5090 Cooling, BeeLlama VRAM Opts, Resizable BAR Performance Gains

RTX 5090 Cooling, BeeLlama VRAM Opts, Resizable BAR Performance Gains

Today’s Highlights

NVIDIA’s upcoming RTX 5090 cooling solutions are detailed, while driver-level optimizations like Resizable BAR deliver significant performance boosts for RTX 5080 users. On the software front, BeeLlama v0.2.0 demonstrates impressive VRAM optimization and inference speedups on the RTX 3090, pushing the boundaries of local LLM performance.

BeeLlama v0.2.0 – DFlash Update Boosts LLM TPS on RTX 3090 (r/LocalLLaMA)

Source: https://reddit.com/r/LocalLLaMA/comments/1tkpz2y/beellama_v020_major_dflash_update_single_rtx_3090/

This update introduces BeeLlama v0.2.0, a significant advancement in local LLM inference, particularly highlighted by its “DFlash” optimization. Running on a single NVIDIA RTX 3090, the new version delivers impressive performance gains for popular open-source models. Benchmarks show Qwen 3.6 27B achieving up to 164 tokens per second (tps), a 4.40x improvement, and Gemma 4 31B reaching 177.8 tps, a 4.93x increase over previous versions. This demonstrates a substantial leap in processing speed for LLM generation.

The core improvement stems from the DFlash update, which likely refers to optimizations in data transfer or memory access patterns within the GPU’s VRAM, crucial for handling large language models efficiently. While prompt processing speed remains near baseline, the focus on generation speed is paramount for interactive LLM applications. This project, available on GitHub, offers a practical tool for developers and enthusiasts looking to maximize their consumer-grade GPU’s potential for high-performance LLM inference, making larger models more viable for local deployment without requiring expensive data center hardware.

The ability to run 27B and 31B parameter models at such high speeds on a single 24GB RTX 3090 is a testament to the continuous innovation in VRAM optimization techniques. These advancements are critical for democratizing access to powerful AI models, allowing researchers and hobbyists to experiment and develop without prohibitive computational costs. The BeeLlama project directly addresses the challenge of fitting and efficiently running large models within the constraints of consumer GPU memory and bandwidth.

Comment: This update showcases how targeted software optimizations can unlock substantial performance gains for LLM inference, making higher-parameter models more accessible on consumer GPUs like the RTX 3090, especially by improving VRAM utilization.

AORUS Details RTX 5090 Infinity GPU Cooling, Targets 77°C Under Load (r/nvidia)

Source: https://reddit.com/r/nvidia/comments/1tkrvwc/aorus_details_rtx_5090_infinity_graphics_card/

AORUS has begun to reveal details about its upcoming flagship graphics card, the RTX 5090 Infinity, offering a glimpse into the cooling solutions designed for NVIDIA’s next-generation GPU. The most notable detail is the claim of maintaining a maximum GPU temperature of 77°C under intense load, specifically during a Furmark stress test. This thermal target is ambitious for a top-tier card, suggesting a highly robust and efficient cooling system will be paramount to handle the anticipated power demands of the RTX 5090.

High-performance cooling solutions are increasingly critical as GPUs push higher power envelopes to deliver leading computational power. Maintaining lower operating temperatures not only ensures sustained boost clocks and prevents thermal throttling, but also contributes to the longevity of the hardware. For enthusiasts and power users, efficient cooling translates directly into greater stability and potential for overclocking, allowing them to extract even more performance from their investment.

This early detail from AORUS provides an important data point on the expected thermal engineering required for the Blackwell architecture. As NVIDIA prepares to launch its 50-series GPUs, focusing on cooling performance underscores the challenges and innovations in balancing raw power with thermal management. It also sets expectations for other AIB partners regarding the cooling capabilities necessary for the RTX 5090, indicating a fierce competition in thermal design for the next generation of high-end graphics cards.

Comment: Achieving 77°C under Furmark is ambitious for a flagship, suggesting a robust cooler design to handle the likely high TDP of the RTX 5090. This sets a strong benchmark for thermal performance in the next generation.

Resizable BAR Delivers Up to 30% Performance Boost for RTX 5080 in Forza Horizon 6 (r/nvidia)

Source: https://reddit.com/r/nvidia/comments/1tkf3ug/forza_horizon_6_resizable_bar_on_vs_off_massive/

A recent report highlights a “massive” performance uplift of up to 30% in Forza Horizon 6 by simply enabling Resizable BAR (ReBAR) on an NVIDIA RTX 5080 graphics card. Resizable BAR is a PCI Express feature that allows the CPU to access the entire GPU frame buffer at once, rather than being limited to 256MB chunks. This can significantly improve data transfer efficiency between the CPU and GPU, leading to performance gains in specific applications and games that can leverage the increased bandwidth.

The “free” nature of this performance boost is particularly noteworthy, as it requires no hardware upgrade beyond ensuring compatibility of the motherboard, CPU, and GPU, and then enabling the feature in the system’s BIOS/UEFI and graphics drivers. While the exact performance gains can vary widely between games, resolutions, and system configurations, a 30% improvement is substantial and makes a compelling case for all compatible users to enable ReBAR.

This finding underscores the importance of optimizing the entire system pipeline, from hardware architecture to driver implementation. NVIDIA, AMD, and Intel have all embraced ReBAR (or Smart Access Memory for AMD), recognizing its potential to unlock latent performance in modern systems. For users with an RTX 5080 and a compatible platform, verifying and enabling Resizable BAR is a straightforward step to enhance gaming performance without additional cost, showcasing how software and firmware optimizations continue to play a crucial role in maximizing GPU output.

Comment: It’s impressive to see such a significant, ‘free’ performance gain from simply enabling Resizable BAR. This underscores the importance of proper system configuration and driver-level optimizations for modern GPUs.

This week in Cursor + .NET — 3 rules + 4 essays (week ending May 22, 2026)

Every weekday a single, opinionated rule for senior C#/.NET engineers using Cursor. Here’s the full week in one read — canonical posts live on the Agentic Architect blog.

New essays this week

Teach Cursor Result<T> instead of throwing

Thu 21 May · C# patterns

Stop the AI from undoing your Result/ErrorOr error model with throw and null on every new prompt.

Seven words that stop Cursor hallucination loops

Wed 20 May · Cursor rules

The correction spiral — and the circuit-breaker rule that ends it before you type the stop phrase.

The Scoped→Singleton DI bug your AI just suggested (and how to catch it)

Tue 19 May · .NET DI

The .NET lifetime bug that ships to production silently — and the one Cursor rule that catches it before merge.

The Context Tax: Why every Cursor session costs you 15 minutes

Mon 18 May · Architecture

The hidden cost senior engineers pay every morning — and a four-rule architecture for eliminating it.

3 daily senior rules

Rule 9: Scoped Capture in Singleton

Fri 22 May

The single most expensive .NET runtime bug: a Singleton holding a Scoped service. Cursor cheerfully writes this without warning. Audit constructor parameters of any class registered as Singleton — if any are typically Scoped (DbContext, repositories, MediatR sender), flag it before merge.

→ Permalink on the blog

Rule 8: CancellationToken Propagation

Thu 21 May

Every async method in your codebase should accept and forward a CancellationToken. Make it a rule that any new async signature without one is flagged. Stops the AI from quietly losing cancellation half-way down a call chain.

→ Permalink on the blog

Rule 2: Persistence Boundaries

Wed 20 May

Never let the AI write database logic in your Controllers. Enforce a strict boundary where all IQueryable access stays in the Infrastructure layer. This keeps your business logic “pure” and readable for the LLM.

→ Permalink on the blog

Try one rule before you trust the whole kit

The free arch-core-lite.mdc is one drop-in Cursor rule that ends the morning re-explanation ritual. Install in 60 seconds, see whether Cursor actually remembers your DI lifetimes, and decide for yourself whether the full kit is worth £19.99.

Canonical home for everything in this digest: https://agenticstandardcontact-byte.github.io/agentic-architect/blog/.

RAG Architecture with n8n + PostgreSQL (pgvector) + Ollama Gemma4 on AWS EC2

Figure 1: Architecture of two AWS EC2, one running gemma4 and the other N8N

This is a submission for the Gemma 4 Challenge: Write About Gemma 4

A Complete Enterprise AI Knowledge Retrieval Architecture for Private Document Intelligence

Summary
This article explains a Retrieval-Augmented Generation (RAG) architecture using n8n, PostgreSQL with pgvector, Ollama, and Gemma4 running on AWS EC2. The platform automatically ingests emails and PDFs, creates embeddings, stores vectors in PostgreSQL, and retrieves contextual information to generate AI answers grounded in enterprise data.

Content
You can view a video of this Gemma4 architecture here:
https://www.youtube.com/watch?v=bTP-sNKlsxc

RAG architectures combine vector search with large language models. In this solution, n8n orchestrates ingestion workflows and query processing. Emails and PDF documents are read automatically, text is extracted and cleaned, then split into semantic chunks. The chunks are embedded using the nomic-embed-text model and stored in PostgreSQL pgvector. When users ask questions, the question is embedded and compared against stored vectors to retrieve the most relevant chunks. Gemma4 then generates a final response using retrieved context.
The architecture uses two AWS EC2 instances. The first server hosts n8n, PostgreSQL, Docker, and orchestration services. The second server hosts Ollama, Gemma4, and the embedding model. This separation improves scalability and isolates AI workloads from orchestration tasks.
Docker containers simplify deployment and maintenance. PostgreSQL with pgvector enables semantic similarity search directly inside the relational database. This architecture is modular and can evolve with future embedding models and LLM technologies.

Business Applications
1.Customer Support AI
Support teams can query manuals, troubleshooting guides, and ticket histories using natural language to accelerate customer assistance.
2.Enterprise Knowledge Management
Organizations can centralize contracts, policies, reports, and procedures into an intelligent AI search platform.
Financial Analytics
Executives can ask natural language questions about sales trends, ERP reports, invoices, and operational metrics.
Technical Details
Infrastructure Requirements:

  • EC2 #1: t3.large or t3.xlarge with PostgreSQL, pgvector, Docker, and n8n.
  • EC2 #2: GPU-enabled instance such as g6e.2xlarge for Ollama and Gemma4.
  • Ubuntu 22.04 recommended.
  • SSD storage and private VPC networking.

Implementation Details:
n8n automates email ingestion, PDF extraction, chunking, embedding generation, and vector storage. Chunk sizes around 1000 characters with overlap improve semantic retrieval. PostgreSQL pgvector performs cosine similarity searches. Gemma4 receives contextual prompts generated from retrieved chunks.
Security and Networking:
Use HTTPS with reverse proxies, encrypted EBS volumes, private networking between EC2 instances, and restricted security groups to protect sensitive enterprise data.
Estimated Costs:

  • EC2 #1 daily cost: approximately USD $2–$3.
  • EC2 #1 monthly cost: approximately USD $60–$90.
  • EC2 #2 GPU server daily cost: approximately USD $25–$40.
  • EC2 #2 monthly cost: approximately USD $750–$1,200.
  • Total monthly infrastructure: approximately USD $850–$1,400 depending on workload.

Figure 1: Architecture of two AWS EC2, one running gemma4 and the other N8N
Figure 1: Architecture of two AWS EC2, one running gemma4 and the other N8N

COMPLETE STEP-BY-STEP FLOW
STEP 1 — User Sends Data Into the System

According to the infographic:

Emails with PDFs are read on EC2 #1.

This is the beginning of the Ingestion Workflow.

The company may receive:

invoices
manuals
contracts
reports
customer emails
technical documentation
support tickets

n8n automatically monitors:

IMAP mailboxes
folders
APIs
SharePoint
Google Drive
CRMs
ERPs
What n8n Does

n8n acts as the automation orchestrator.

Example:

New email arrives
n8n detects it
Downloads PDF attachment
Starts the AI pipeline automatically

No human intervention is required.

*STEP 2 — PDF Text Extraction
*

The infographic shows:

Extract PDF Text

At this stage:

PDFs are parsed
text is extracted
metadata is collected

Metadata may include:

sender
date
filename
document type
department
customer ID
Why This Matters

LLMs cannot directly understand PDFs.

The system must convert documents into raw text before AI processing.

Example:

A 200-page manual becomes machine-readable text.

_STEP 3 — Clean and Normalize Text
_
The infographic shows:

Clean & Normalize Text

Raw PDF extraction is usually messy.

Problems include:

broken lines
duplicated spaces
headers/footers
page numbers
encoding problems
tables split incorrectly

n8n cleans the content using scripts or functions.

Example

Before cleaning:

Invoice #2939

Customer:
ACME Corp

Page 1

After cleaning:

Invoice #2939 Customer: ACME Corp
STEP 4 — Chunking the Text

The infographic shows:

Chunk Text

This is one of the MOST important steps in RAG.

Why Chunking Is Necessary

LLMs have token limits.

A 500-page document cannot be sent entirely to the model.

So the document is split into smaller pieces called:

Chunks

Example chunk size:

1000 characters
200 overlap
What Overlap Means

Suppose chunk #1 ends with:

The warranty expires after…

Chunk #2 begins with:

…after 24 months of operation.

Overlap preserves semantic continuity.

Without overlap:

information can be lost
meaning breaks between chunks
STEP 5 — Create Embeddings

The infographic shows:

Prepare Embedding Payload
Call Embedding Server

This is where semantic AI begins.

What Is an Embedding?

An embedding converts text into mathematical vectors.

The embedding model understands meaning.

Example:

“car”

and

“vehicle”

generate similar vectors.

Embedding Process

Chunk text is sent from EC2 #1 to EC2 #2.

The embedding server uses:

nomic-embed-text

to transform text into vectors.

Example:

[0.023, -0.991, 0.224, …]

These vectors may contain:

768 dimensions
1024 dimensions
1536 dimensions

depending on the model.

Why Embeddings Are Powerful

Traditional search uses keywords.

Embeddings use:

Semantic Meaning

This means users can ask:

How long is the warranty?

Even if the document says:

Coverage remains valid for 24 months.

The system still finds the answer.

_STEP 6 — Store Embeddings in PostgreSQL pgvector
_
The infographic shows:

Store Embeddings in PostgreSQL (pgvector)

Now the vectors are saved in PostgreSQL.

What Is pgvector?

pgvector is an extension for PostgreSQL that adds:

vector storage
similarity search
AI search capabilities

Example table:

id chunk_text embedding
1 warranty info [0.12, …]
Why PostgreSQL Is Used

Advantages:

mature database
ACID compliance
reliability
backups
indexing
SQL support
enterprise-ready

Instead of needing a separate vector DB like Pinecone or Weaviate, pgvector keeps everything inside PostgreSQL.

_STEP 7 — User Asks a Question
_

The infographic says:

User sends question (HTTPS POST /ask)

A user opens the web interface and types:

What is the warranty period for industrial pumps?

The question goes to EC2 #1.

STEP 8 — Create Embedding for the Question

The infographic shows:

Create Embedding for Question

The question itself is transformed into a vector using the SAME embedding model.

This is critical.

If documents and questions use different embedding models:

similarity breaks
retrieval quality drops
*STEP 9 — Vector Similarity Search
*

The infographic shows:

Vector Search in PostgreSQL

This is the core of RAG.

How Similarity Search Works

The question vector is compared against ALL stored chunk vectors.

Using:

cosine similarity
Euclidean distance
inner product

PostgreSQL finds the chunks mathematically closest in meaning.

Example

User asks:

How many vacation days do employees receive?

The database may retrieve:

Employees are entitled to 15 annual leave days.

even without keyword matching.

STEP 10 — Build Context

The infographic shows:

Build Context

The best matching chunks are combined together.

Example:

Chunk 1: vacation policy
Chunk 2: HR policy
Chunk 3: employment handbook

The system assembles them into context.

Why Context Is Critical

LLMs hallucinate when lacking information.

RAG prevents hallucinations by giving:

Relevant Ground Truth Data

The model answers from company knowledge.

_STEP 11 — Build Prompt for Gemma4
_

The infographic shows:

Build Prompt for Gemma4

A structured prompt is generated.

Example:

You are an enterprise assistant.

Answer ONLY using the provided context.

Context:
[retrieved chunks]

Question:
How many vacation days do employees receive?

This prompt engineering layer is extremely important.

*STEP 12 — Send to Gemma4 via Ollama
*

The infographic shows:

Send to Gemma4 (EC2 #2)

The prompt is sent to Ollama.

Ollama exposes APIs like:

/v1/chat/completions

Gemma4 processes:

context
instructions
user question

Then generates the final response.

Why Ollama Is Important

Ollama simplifies:

local LLM serving
model management
GPU usage
API exposure

Without Ollama:

running LLMs locally is much harder.

STEP 13 — Return Answer to User

The infographic ends with:

Answer is returned to the user

The final answer travels back:

Gemma4 → EC2 #1 → Web Client

The user receives a grounded response.

Example:

Employees receive 15 vacation days annually after completing one year of employment.
Why This Architecture Is Powerful

This architecture creates:

Private AI

Data stays inside AWS infrastructure.

Semantic Search

Searches by meaning, not keywords.

Scalable AI

You can scale:

database
workflows
LLM server
embedding server

independently.

Conclusions
This RAG architecture demonstrates how organizations can build private and scalable AI systems using open-source technologies. The combination of n8n, PostgreSQL pgvector, Ollama, and Gemma4 enables intelligent retrieval of enterprise knowledge while maintaining full infrastructure control. The modular design supports future scalability, model upgrades, and advanced AI workflows.