What Breeders Actually Need From Software (And What Developers Assume They Need)

It’s 11pm. A breeder has three browser tabs open, a Google Sheet with color-coded columns, and a notebook sitting next to the keyboard with handwritten pairing notes from two seasons ago. They’re trying to figure out whether a planned breeding will push the coefficient of inbreeding above a threshold they’ve set for their program. Nothing on their screen talks to anything else. They’ve been doing this for years.

Not because they haven’t looked for better options. They have. They’ve tried CRMs, inventory apps, animal management platforms, and general-purpose databases. Every tool either bends the problem into something it wasn’t, or buries the actual work under features built for a different kind of business entirely.

This is the starting point for almost every serious breeder I’ve talked to. And it’s the starting point for understanding why software built for breeders keeps failing them.

What Developers Assume Breeders Need

The reasonable guesses aren’t wrong. They’re just incomplete.

A developer approaching the breeder space for the first time would probably reach for a familiar toolkit. A CRM to track customers and waitlists. A database or spreadsheet for animal records. A calendar for scheduling. A storefront for selling. Maybe a notes field or two.

These tools exist. Some of them are excellent at what they do. Breeders have tried them. The failure point is always the same: these tools treat breeding like inventory management. Animals become product records. Bloodlines become tags. The actual craft, the decision-making, the verification, the longitudinal tracking that spans years and generations, falls completely through the cracks.

The gap isn’t a missing feature. It’s a missing frame of reference.

What Breeders Actually Need

1. Lineage integrity, not just lineage storage

A field in a database that says “Sire: Rocky” is not lineage. It’s a note.

Real lineage is verified, multi-generational, and tamper-resistant. It is the foundation of the animal’s value. When a buyer pays a premium for a dog, a gecko, or any production animal, they are buying the bloodline as much as the animal itself. An unverifiable or inconsistently documented pedigree doesn’t just weaken a sale. It erodes trust in the entire breeding program.

This is why registries exist. The AKC has been solving this problem for 140 years. ABKC built it from scratch for a new breed. The model works: verified registration, traceable multi-generation pedigrees, records that transfer with the animal. What breeders need from software is a version of that infrastructure that works at the program level, not just at the registry level.

Storing a sire and dam field is not lineage. Lineage is structural. This is the core problem that ReptiDex solves with multi-generation pedigree trees and cross-collection lineage linking, and it’s the foundation of the registry and pedigree platforms I build for breed clubs.

2. Pairing logic, not just pairing records

Breeders don’t just need to log who was bred to whom. They need to understand what a pairing means before it happens.

Coefficient of inbreeding (COI) calculations. Trait probability distributions. Genetic incompatibility flags. Restrictions on first-generation linebreeding, which organizations like the Gold Standard Gecko Club have built into their competition rules precisely because it matters. A form with a sire field and a dam field captures none of this.

The pairing decision is where the breeding program lives or dies. The software either helps you make it well or it doesn’t help you at all. Most software doesn’t help at all. The breeding records and genetics apps I build for breeders start here, with trait probability, COI awareness, and genetic compatibility checks built into the pairing workflow.

3. Clutch and litter tracking built for biology, not inventory

A litter is not a batch. A clutch is not a shipment.

Offspring need to be tracked individually, from first record to final placement, with their own records linking directly back to parents. Weights at hatch or birth. Dates. Morphs or phenotypes. Retained animals. Placed animals. Animals lost. Each one is a data point in the lineage tree. Each one has downstream consequences for the program.

Generic inventory tools treat offspring as a transaction. You record the sale, close the ticket, move on. But a breeder may be tracking animals they placed five years ago because the buyer wants to breed back into the line, or because they’re building a multi-generation study, or because that animal’s offspring just showed up at a show and they want the record.

The biology doesn’t end at the sale. The software has to reflect that.

4. Show and competition history that travels with the animal

A dog’s show record is part of its value. So is a gecko’s placement history. Judges, events, placements, titles, pointed wins, majors. That history needs to live on the animal’s profile, not in a separate spreadsheet, not in someone’s email archive.

When a buyer is evaluating a stud or a broodmother, they want to see the full picture. When a registry is verifying eligibility for competition, they need documented proof. When a breeder is making pairing decisions, the show record of both animals is relevant information.

No CRM is designed to think about an individual animal as a long-term record of achievement. That’s not a CRM problem. CRMs are built for people, not animals. The category mismatch is total.

5. Waitlist management that respects how breeders actually sell

Breeder waitlists are not e-commerce carts. Shopify cannot model them. A checkout flow cannot capture them.

A waitlist for a specific pairing might start before the animals are even bred. There are deposits, which may or may not be refundable depending on outcome. There are first-right-of-refusal arrangements. There are cohort assignments, where buyers pick pick order rather than picking specific animals. There are communication threads tied to a specific pairing that need to stay connected to the records, not float off into a general inbox.

And when the clutch or litter doesn’t go as planned, because sometimes it doesn’t, all of that needs to be renegotiated, documented, and communicated. A shopping cart abandonment workflow is not going to help you here. This is exactly why I built Geckistry as a custom sales platform from scratch rather than forcing my gecko business onto Shopify.

Why the Gap Exists

This is not a problem of bad developers. It is a structural problem.

You cannot spec out what you have never lived. A developer who has never sat with a stud book, never calculated a COI, never navigated a waitlist dispute when a litter came out smaller than projected, does not know what questions to ask. They build what makes sense from the outside. It looks reasonable. It fails in practice, quietly, in ways that don’t always surface in a demo or a trial period.

The domain knowledge is not a bonus. It is the product.

This pattern shows up in every industry where the work is specialized. Healthcare software built without clinical input produces tools that technically meet requirements and fail at the bedside. Legal technology built without practicing attorneys builds workflows that don’t map to how cases actually move. The breeder space is no different. The gap between what software promises and what breeders actually need is almost always a gap in domain understanding, not engineering capability. That gap is the entire reason Built By Dusty exists.

What Staying on Spreadsheets Actually Costs

The spreadsheet and notebook system works until it doesn’t. Most breeders don’t feel the cost of it until something breaks.

Hours per week on manual data entry that should be automatic. Lineage errors that surface years later and are nearly impossible to trace. Pairing decisions made without full genetic context because the information exists but isn’t connected. Waitlist disputes because the terms were never formally documented. Records that live in one person’s head and disappear when a hard drive fails or a phone breaks.

The competition for better breeder software is not other software. It is the status quo. And the status quo has real costs that most breeders have simply learned to absorb.

The Standard Already Exists

The AKC figured this out in 1884. The ABKC built it for a breed that didn’t exist yet and got it right. The pattern is consistent across every established species club that takes lineage seriously: verified registration, multi-generation pedigree, show records, transferable titles, and a system of trust that makes the record worth something.

What breeders need from modern software is that same infrastructure, updated, accessible at the program level, and integrated into the daily work of running a breeding operation. Not a replacement for registries. An extension of what registries do, built for the breeder who is living the work.

The standard is not new. The software that meets it is.

Built From the Inside

BBD exists because I am a breeder first. I’ve been in dogs since I was five years old. My family bred and showed ADBA American Pit Bull Terriers, moved into American Bullies around 2005 when the breed was still being formed, and I was part of the group that established ABKC during those early years. I’ve made group placements in UKC. I breed crested geckos. I built ReptiDex because I needed it and nothing adequate existed.

ReptiDex launched with 50 paid subscribers and 200 animals tracked in its first nine days. Not because of marketing. Because breeders recognized something built by someone who understood the problem. You can read the full build stories for ReptiDex, Geckistry, and Texas Top Notch Frenchies in the case studies.

The best software for breeders will never come from someone who Googled the problem. It will come from someone who lived it.

If you’re a developer working in this space, this is the bar. If you’re a breeder evaluating your options, this is what to ask for.

I build breeder websites, records and genetics apps, sales platforms, and registry systems through my studio, Built By Dusty. Every one of them is built on software I use in my own breeding program. If you’re a breeder who is ready to replace the spreadsheets, or a breed club that needs real infrastructure, I’d like to hear from you.

The Open-Source Security Guide for Flutter Developers

We spend a lot of time in the Flutter community arguing about state management and app architecture. But when I recently went looking for a centralized list of mobile AppSec tools specifically for Flutter, I hit a wall.

There wasn’t a dedicated “Awesome” repository for Flutter security. The resources for both defending and reverse-engineering compiled Dart apps were completely scattered.

So, instead of hoarding my personal bookmarks, I made the repo myself.

Meet Awesome Flutter Security.

It’s a curated, open-source list of Flutter application security resources, defensive tools, and vulnerable sandboxes. Whether you are a developer trying to lock down your app or a pentester trying to break one, I wanted everything in one place.

What’s inside:

  • Defensive Tools: RASP (Runtime Application Self-Protection), obfuscation guides, and the right ways to handle secure storage and biometrics.
  • Offensive Tools: Frameworks like reFlutter and blutter for intercepting traffic, bypassing SSL pinning, and reverse-engineering AOT binaries.
  • Practice Sandboxes: Intentionally vulnerable apps (like DVFA) mapped to the OWASP Mobile Top 10 so you can practice your hacking skills.
  • Standards: The must-read guidelines from OWASP and the official Flutter team.

Let’s build this together

The goal is to make this the standard AppSec reference for the Flutter ecosystem. If you know of a tool, a great article, or a package that belongs on this list, PRs are highly welcome!

Check out the repository here: Awesome Flutter Security

Drop a ⭐️ if you find it useful, and let me know in the comments: what is your go-to package for securing your Flutter apps? Did I miss any hidden gems?

How npm, pnpm, and yarn Ate 40GB of My 256GB SSD

Last week my MacBook started complaining: “Your disk is almost full.”

I had 8GB free. On a 256GB machine. I hadn’t downloaded any movies or photos. What was going on?

The Investigation

I started hunting. First suspect: node_modules.

find ~ -name "node_modules" -type d -exec du -sh {} ; 2>/dev/null

The results made me want to cry:

~/projects/2022-client-work/node_modules              1.2GB
~/projects/abandoned-react-app/node_modules          890MB
~/projects/experiment-three-js/node_modules          750MB
~/projects/old-work-project/node_modules             1.8GB
~/projects/that-one-tutorial/node_modules            420MB
# ...20 more entries

25GB of node_modules from projects I hadn’t touched in months. Some were from 2022.

Then I checked the package manager caches:

npm cache verify    # 3.2GB
pnpm store prune    # Would free 5GB
yarn cache clean    # 2.1GB

Another 10GB just sitting in package manager caches.

In total: 40GB of JavaScript build artifacts and caches. On a 256GB SSD, that’s 15% of my entire disk — gone to a dependency graveyard.

The Three Package Managers Problem

If you work with JavaScript/TypeScript, you know this pain. You try npm. Then pnpm for speed. Then yarn for work. Each one maintains its own cache in a different location:

  • ~/.npm — npm’s cache
  • ~/Library/pnpm — pnpm’s store
  • ~/Library/Caches/Yarn — yarn’s cache

Plus every project has its own node_modules. You npm install once, build, deploy… and that folder sits there forever. Multiply by 20+ projects over 3 years.

I found a React project from 2022 with 1.8GB of node_modules. I had run npm install exactly once, built the project, and never touched it again. That 1.8GB sat on my SSD for 3 years.

Xcode Wasn’t Innocent Either

While I was at it, I checked Xcode’s cache:

du -sh ~/Library/Developer/Xcode/DerivedData
# 47GB

So my actual breakdown was:

  • node_modules: 25GB
  • npm/pnpm/yarn caches: 10GB
  • Xcode DerivedData: 47GB
  • Docker images: 8GB
  • Rust/Python/Go build artifacts: 5GB

95GB of dev cache on a 256GB machine. My actual code? Under 3GB.

The Manual Cleanup (Don’t Do This)

I spent a Saturday manually cleaning:

# Delete old node_modules... carefully
rm -rf ~/projects/2022-*/node_modules

# Clean package manager caches
npm cache clean --force
pnpm store prune
yarn cache clean

# Wait, where does pnpm store things again?
# And did I just break something?

It took 3 hours. I was paranoid about deleting the wrong thing. And I knew I’d have to do it again in 6 months.

Building DevCleaner

I wanted a tool that would:

  1. Find everything automatically — node_modules, npm cache, pnpm store, yarn cache, and 40+ other dev tools
  2. Show me before deleting — no surprises, no “oops I deleted the wrong folder”
  3. Move to Trash first — so I can verify nothing broke before emptying
  4. Be fast — scan my entire disk in seconds, not hours

So I built it. In Nim, because I wanted to learn something new and ship something fast.

The Results

First scan: 63GB of cleanable cache.

I reviewed the list — all old projects, all safe to delete. Clicked “Clean All”, everything moved to Trash. Verified my current projects still worked. Emptied Trash.

63GB back. My 256GB MacBook finally had breathing room again.

See it in action:

Sovereign Attention Firewall: A Zero-Trust AI Perimeter for Your Calendar

System Architecture

This is a submission for the Notion MCP Challenge

What I Built

The Sovereign Attention Firewall — a zero-trust AI perimeter that defends your calendar and inbox from Calendar Snipers (unverified external invites) and Ghost Projects (meetings tied to archived work), before they ever interrupt deep work.

Why this exists: Procurement professionals, operations leads, and anyone with a visible business title knows the pain. ZoomInfo scraped your LinkedIn. Now your calendar is bleeding ghost meetings, your inbox drowns in “just circling back” sequences, and every cold SDR thinks they own 30 minutes of your Tuesday. The Reddit procurement community has a name for it: attention theft. The only current defenses are manual — reply templates, block lists, and sheer emotional labour.

The real cost isn’t the emails. It’s the cognitive fragmentation. Every unvetted vendor ping is a context switch tax on your focused work.

What it does: The Sovereign Attention Firewall creates a human-in-the-loop AI enforcement system that:

  • Intercepts every external calendar invite and runs it through a zero-trust identity check
  • Detects Identity Phantoms (invites from unverified or suspicious organizers) and Ghost Projects (meetings tied to archived/completed work)
  • Quarantines flagged invites into a Notion Waiting Room for human review — nothing is blocked without your approval
  • Executes silent enforcement: rejected invites are deleted with sendUpdates: false, giving no signal back to the sender that your address is active
  • Escalates repeat offenders automatically to a permanent Block List after two rejections
  • Maintains a daily Sovereign Security Log in Notion — a full audit trail of what was caught, why, and what action was taken

The default flips: your calendar becomes as defensible as your infrastructure.

Video Demo

View on YouTube

Show Us the Code

🔗 github.com/olawolemoses/sovereign-attention-firewall

The system is built with:

  • Cloudflare Workers (TypeScript) for:

    • identity-oracle — deterministic identity registry; checks email allowlists, falls back to domain whitelists, returns Unverified for unknowns. Verdicts are cached in Cloudflare KV for sub-second performance.
    • sovereign-bouncer-mcp — custom MCP server enforcing Bearer auth and trust logic, deployed at the edge
  • Notion Agent + Notion databases as the governance and decision layer — the orchestration core

  • Zapier (Webhook + Paths) as the enforcement bridge across Google Calendar and Gmail

  • Google Calendar + Gmail for event handling, silent enforcement, and RSVP management

How I Used Notion MCP

Notion MCP is not a peripheral integration here. It is the orchestration core of the Sovereign Attention Firewall.

Every external meeting invite is evaluated through a Notion-governed workflow combined with a custom MCP trust check:

  • The Agent calls verify_email_trust(email) on Sovereign Bouncer (MCP)
  • Sovereign Bouncer queries the Identity Oracle and returns trust verdicts
  • Decisions and full policy reasoning are persisted in Notion for human review and auditability
  • When a human updates the Decision property in the 📥 Waiting Room DB from Pending to any terminal state (Approved, Rejected, Blocked, or Cancelled), a native Notion automation fires a webhook to Zapier — passing event metadata and the decision downstream for enforcement

System Architecture

The MCP + Notion integration specifically unlocks:

1. Deterministic policy enforcement

The Agent operates from explicit policy records in the 🛡️ Sovereign Policy DB — P1: Identity Proof, P2: Ghost Hunter, P3: Context Tax — rather than ad-hoc AI judgment. Policies are readable and editable by any team member directly in Notion.

Sovereign Policy DB

2. Persistent operational memory

The 📥 Waiting Room DB stores event metadata, policy reasoning, and decision state across every interaction. Nothing disappears into a black box — every triage decision is traceable over time.

Waiting Room DB

3. Human-in-the-loop governance

A human updates the Decision property in Notion — that single gesture triggers the entire enforcement chain downstream. State-lock behavior in the Agent Constitution prevents the AI from ever re-auditing a decision a human has already made.

4. Context-aware Ghost Project detection

The 📂 Projects DB allows the Agent to match incoming meeting invites against archived or completed project context. A meeting tied to a project marked Archived in Notion is automatically treated as a Ghost Project — no manual flagging required.

Projects DB

5. Automated enforcement with clean separation of concerns

Notion decides. Zapier enforces.

Zapier Enforcement Structure

Three enforcement paths execute based on the human’s decision in Notion:

Path A — Block/Reject: Delete the calendar event silently (sendUpdates: false) + find and delete the source email. No activity signal leaks to the sender.

Path B — Approve: Mark the event as accepted via a PATCH request, preserving full event metadata.

export async function updateEventStatusToAccepted({
  calendarId,
  eventId
}: {
  calendarId: string;
  eventId: string;
}): Promise<{ result: string }> {
  const url = `https://www.googleapis.com/calendar/v3/calendars/${calendarId}/events/${eventId}`;

  const requestBody = {
    attendees: [
      {
        email: calendarId,
        responseStatus: "accepted"
      }
    ]
  };

  const response = await fetchWithZapier(url, {
    method: "PATCH",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(requestBody)
  });

  await response.throwErrorIfNotOk();
  return { result: "Attendee response status updated to 'Accepted'" };
}

Path C — Cancel: Update RSVP to declined, signaling a professional boundary without ghosting.

export async function updateEventRSVPStatus({
  calendarId,
  eventId
}: {
  calendarId: string;
  eventId: string;
}): Promise<{ result: any }> {
  const url = `https://www.googleapis.com/calendar/v3/calendars/${calendarId}/events/${eventId}`;

  const requestBody = {
    attendees: [
      {
        email: calendarId,
        responseStatus: "declined"
      }
    ]
  };

  const response = await fetchWithZapier(url, {
    method: "PATCH",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(requestBody)
  });

  await response.throwErrorIfNotOk();
  return { result: await response.json() };
}

6. Security-aware silent enforcement

sendUpdates: false on all rejection actions ensures unverified senders never receive confirmation that your email address is active. This prevents the sender verification loops that most calendar tools inadvertently create.

7. Daily security intelligence

The Sovereign Security Log auto-generates a daily brief in Notion — phantoms blocked, ghost projects defended, system health status — giving you full situational awareness without opening a dashboard.

Sovereign Security Log

Core insight:
Most productivity systems optimize scheduling. The Sovereign Attention Firewall optimizes attention defense — combining edge policy execution (Cloudflare Workers), governance memory (Notion), and action enforcement (Zapier) into a system where your calendar is treated as a security perimeter, not an open invitation.

Your Turn

I’d love to hear from the community:

  1. How do you currently handle calendar spam and unsolicited vendor invites? Is this a problem you’ve solved, or one you’ve accepted?
  2. Where would you draw the human-in-the-loop line? At what trust level would you feel comfortable letting the AI auto-reject without your review?
  3. What’s missing from this system? What would make the Sovereign Attention Firewall genuinely useful for your workflow?

Hangfire Had a DB Support Problem. I Fixed It. You’re Welcome.

HangFire proper is hugely popular but the official implementation only supports Microsoft SQL Server. They could have made it much more database independent, but didn’t. I suspect the original authors were scratching an itch. Hangfire feels to me like someone who either didn’t want to use scheduled tasks/cron jobs, or didn’t know how. So they wrote something that would act as a cron job inside their code. This led them to only support their environment — they solved their problem for them. Nothing wrong with that — pengdows.crud is also scratching an itch. That doesn’t make software bad. It means it wasn’t born of careful planning to support everything from day one, it is “I need this, it doesn’t exist, let me write it.” The difference is the itch. Hangfire’s itch was “I need a job scheduler in my environment.” pengdows.crud’s itch was “nobody handles cross-database work in .NET correctly.” One of those itches produces a single-database solution. The other one doesn’t.

Let’s be honest about what the two biggest problems with Hangfire actually are. First, connection handling — pool exhaustion under spike load, connection leaking, and single-writer databases like SQLite falling apart under write contention. Second, lock contention — distributed lock implementations that produce violations, deadlocks, or overlapping ownership under burst load. I am going to tell you I solved both. Then I am going to show you the receipts.

When other people started extending Hangfire to work with their DBs, those people had to re-solve problems that had already been solved elsewhere. The road to hell is paved with good intentions, and the Hangfire storage ecosystem is well-paved. Here is what the community has produced:

Database Package Status
SQL Server Hangfire.SqlServer (official) ✅ Maintained
PostgreSQL Hangfire.PostgreSql ✅ Maintained
MySQL Hangfire.MySqlStorage ⚠️ Known deadlock bugs
MySQL Hangfire.Storage.MySql ⚠️ Fork created to fix the above, stuck in beta, author moved on
SQLite Hangfire.Storage.SQLite ⚠️ Alive but threadbare
Firebird Hangfire.Firebird ☠️ Dead since 2015
Oracle Hangfire.FluentNHibernateStorage ☠️ Via NHibernate, last real work 2022, SQLite/Access/SQL CE broken by its own README
Dameng DMStorage.Hangfire ❓ Chinese ecosystem only

That isn’t the edge case, it is systemic. MySQL has two packages because the first one had deadlock bugs bad enough that someone forked it. The fork has been stuck in beta for years. The author’s own README says he got fed up and wrote a different scheduler entirely. The NHibernate-backed provider claims to support six databases — its own README admits that SQLite, MS Access, and SQL Server Compact “proved not to work” and there’s no plan to fix them. As a sidenote, SQL CE requires careful handling most people never handle correctly, my SingleWriter mode. Firebird hasn’t been touched since 2015. They still install. Whether they behave correctly against a current version of their target database is a question you get to answer in production.

The SQLite Detour

So when I started readying pengdows.crud 2.0, I really wanted to show off my new SingleWriter mode. If you aren’t familiar with pengdows.crud that is ok, go check it out on Github (https://github.com/pengdows/pengdows.crud). My crud has 5 different connection modes reflecting the reality of database behavior:

  • SingleConnection — all database work has to be done via a single connection. This is the mode that SQLite and DuckDB :memory: databases have to use. If you try to connect a second connection you literally get a new DB.
  • SingleWriter — these databases can have as many readers as you like (within reason), but all writes have to be serialized. If two connections try to write simultaneously you either end up with a corrupted database or it throws “database is busy” and one of them fails. Neither is acceptable in production.
  • KeepAlive — created for SQL Server LocalDB, to keep the server alive. I hold 1 connection open for the life of the app. That connection is never used for anything other than keeping the server alive.
  • Standard — my default mode. Open a connection, run your SQL, consume the results, close the connection the moment it is available to be closed.
  • Best — choose the best one for the DB you are using.

pengdows.crud allows you to change how your app interacts with your DB without changing your code. With 2.0 I revamped some things and that had the effect of really optimizing my single writer — only 1 writer is allowed at a time, and it is NOT a pinned connection, it is controlled through a governor. In short this makes DuckDB and SQLite safe to use under moderate write load, and I have a turnstile that prevents writer starvation.

With this new feature, I was really just looking for a SQLite project to rewrite and show it off. Hangfire is notorious for pool exhaustion. If I can make SQLite work reliably under Hangfire that helps Hangfire users, helps developers, and shows off what pengdows.crud can do.

When I started really digging in though, I found that it was not written as I expected, and a lot of the other storage providers seem to be suffering from code rot and abandonment. I thought to myself — well pengdows.crud supports 14 relational database systems, so lets write it once. I whipped out pengdows.poco.mint (available either as a NuGet command line tool or a self-contained WebUI Docker image), spun up a SQL Server container, ran the scripts to get POCOs based on the tables, and got to work.

The Lock Problem

As I said, Hangfire feels like a scratch-an-itch project meant for one environment. Evidence of this showed up right here. The SQL Server code uses a SQL Server-only stored procedure to keep other processes from grabbing a task. So every other storage implementation has to solve this problem in a new way. It wasn’t even necessary for SQLite since it only allows one writer, but the author created a table named “Lock” to solve the problem anyway — so I borrowed that approach. “Lock” is a reserved word in several of my supported databases, so I renamed it to “hf_lock” and moved on. It is not as fast as the stored procedure on SQL Server, but it is uniform across all 13 supported databases, and the benchmarks show it.

What’s Supported and What Isn’t

pengdows.hangfire supports 13 databases. Here is how that stacks up against what existed before:

Database Had Support Before pengdows.hangfire
SQL Server ✅ ✅
PostgreSQL ✅ ✅
MySQL ✅ ⚠️ ✅
SQLite ✅ ⚠️ ✅
Firebird ✅ ☠️ ✅
Oracle ✅ ☠️ ✅
MariaDB ❌ Never ✅
CockroachDB ❌ Never ✅
DuckDB ❌ Never ✅
YugabyteDB ❌ Never ✅
TiDB ❌ Never ✅
Aurora MySQL ❌ Never ✅
Aurora PostgreSQL ❌ Never ✅

Seven databases that have never had Hangfire storage support before. The ones that did exist either had known bugs, were forks of broken packages, or hadn’t been touched in a decade.

Two databases from the pengdows.crud supported list aren’t in pengdows.hangfire. Dameng has no Docker image to test against and no modern .NET provider. When those exist, adding it is trivial — the door is open. Snowflake is a different problem entirely. pengdows.crud includes a Snowflake dialect, but Snowflake is designed for analytical workloads — columnar storage, warehouse-level concurrency, high per-query latency. Hangfire needs row-level locking, low-latency queue polling, high-frequency small writes and deletes, and reliable distributed lock semantics. These requirements are fundamentally at odds with Snowflake’s architecture. It isn’t a missing SQL feature, it’s the wrong database for the workload. If that changes, the support will follow.

The Receipts

Here is what I said I would show you.

111 abstract facts, instantiated across 11 databases via Testcontainers, producing 1,204 concrete test cases. Real engines, not mocks. Connection behavior, transaction mutations, expiration cleanup, counter aggregation, queue fetch/claim/ack — covered.

That handles correctness. For contention there is a separate stress suite, and that is where it gets interesting.

200 workers. One resource. All contending simultaneously. Required invariants: zero ownership violations, zero interval overlaps, max concurrent owners never exceeding 1. That test passes against SQL Server at full pool size. It passes again with pool size forced down to 40 — where timeouts and pool rejections are expected but successful acquisitions still cannot overlap. It passes with 200 workers spread across 20 resources with 80% of traffic on 2 hot keys. SQLite and DuckDB each have their own 200-worker SingleWriter variants. All pass.

Correctness is verified three ways: live CAS-style ownership conflicts, max concurrent holders per resource, and post-run overlap analysis on recorded hold intervals. You cannot get a false pass on one check and slip through — all three have to agree.

There is also a crash path. Process killed mid-lock, TTL set to 15 seconds — the dead lock was stolen and cleaned up in 14.8 seconds. Lock rows do not orphan.

The MySQL fork in the ecosystem exists because the original had deadlock bugs under burst load. The fork’s author eventually gave up and wrote a different scheduler. These tests are the direct answer to that problem. 40 passed. 0 failed.

These are not one-off validation runs. The unit tests, integration tests, and stress suite are part of the open source library. They run on every change. If you pull the repo, you get the tests.

Why I Built This

So yeah, I wrote this for three reasons:

  1. Help Hangfire users — you now have 13 databases to choose from, connection handling that doesn’t fall apart under load, and lock contention that has been stress tested to 200 concurrent workers.
  2. Help Hangfire developers — pool saturation and lock violations are solved problems if you use the right storage.
  3. Show off pengdows.crud and generate some interest.

This whole thing is me proving out my own scratch-an-itch software. pengdows.crud exists because nobody was handling cross-database work in .NET correctly. pengdows.hangfire exists because I needed a real-world, production-grade project to prove it works. Hangfire users get more database options, better connection handling, and a lock implementation that holds under pressure. The world gets a robust example of what pengdows.crud can actually do. That’s not a bad outcome for an itch.

The package is pengdows.hangfire. It’s on NuGet. Go kick the tires.


Automating BIND9 DNS Management: From Manual Configs to Infrastructure as Code

Managing BIND9 DNS zone files manually doesn’t scale. Every change means SSH-ing into a server, editing config files, and hoping you don’t break DNS resolution for your entire infrastructure.

I built an open-source stack that turns BIND9 management into proper Infrastructure as Code. Here’s what the stack looks like:

The Architecture

The solution has three components that work together:

  1. bind9-api — A REST API that sits on top of BIND9, providing HTTP endpoints for zone management, record CRUD, ACL management, DNSSEC, and more.

  2. Terraform Provider for BIND9 — A Terraform/OpenTofu provider that talks to the API, letting you manage DNS zones and records as code with full plan/apply workflow.

  3. Ansible Role — Handles the one-time deployment of both BIND9 and the API on your servers.

The key design decision: Ansible manages infrastructure (installing BIND9, deploying the API) while Terraform manages content (zones, records, ACLs). Each tool does what it’s best at.

What You Can Do

  • Manage 30+ DNS record types (A, AAAA, CNAME, MX, TXT, SRV, CAA, and more)
  • Single-server or multi-primary architectures
  • DNSSEC key management (KSK, ZSK, CSK)
  • ACL management as code
  • Bulk record generation using Terraform’s for_each and range()
  • Prometheus metrics for monitoring

Getting Started

The full walkthrough with architecture diagrams, code examples, and step-by-step setup is in the blog post on Dev Genius:

Read the full article on Medium

All three projects are open source under Apache 2.0. Contributions and feedback welcome!

Self-Hosting a Vaultwarden Password Manager

xkcd 936: Password Strength

Full text can also be viewed here.

Password vaults are a convenient and secure way to manage multiple passwords. As data breaches become more and more common, security guidance changes lead to an inevitable mishmash of credentials that are impossible to remember when not used daily. The logic behind constantly-evolving password guidelines is beyond the scope of this guide, but recent word from NIST on password vaults recommends their use:

Verifiers SHALL allow the use of password managers and autofill functionality. Verifiers SHOULD permit claimants to use the “paste” function when entering a password to facilitate password manager use when password autofill APIs are unavailable. Password managers have been shown to increase the likelihood that subscribers will choose stronger passwords, particularly if the password managers include password generators

This guide walks through setting up a lightweight, locally-hosted password manager that allows the user (or users) to keep their accesses secure without needing to perform superhuman feats of memorization. It is written assuming the reader has a fully configured WireGuard VPN server on their home network, with all local traffic handled by the VPN specifically. This is necessary for security, not just for Vaultwarden; it’s generally much simpler and safer to stand up your devops infrastructure when you don’t have to open ports to the entire internet.

Background

A password vault (or password manager) is a secure, encrypted digital storage system for username and password combinations. Remembering one password is much simpler than having to remember multiple. Why NIST took so long to come to this conclusion is out of scope for this guide, but feel free to enjoy others’ discourse on the topic.

xkcd 936: Password Strength
Source: xkcd 936

There are several password managers to choose from; Bitwarden is a strong contender in the space, and I highly recommend it for the average person or enterprise. It is open source, has weathered security audits, and you can even self-host it. While I personally dislike hosting anything on the cloud, I don’t have an issue with their model from a security perspective; your data is encrypted locally before it’s even sent to their servers, so even Bitwarden themselves could not access your information.

Some downsides exist, though; it’s a resource hog when hosted locally, and resources matter when you keep stacking services on your home Debian device. The average user does not need the scalability and infrastructure that it provides. Additionally, some services such as autofilling passwords require a paid subscription, even when self-hosting Bitwarden.

Thus, this guide settles on Vaultwarden. Vaultwarden is a lightweight re-write of Bitwarden in Rust. It uses much less CPU and RAM (~50MB to Bitwarden’s ~1-2GB), and as a bonus it is easier to set up. The process is explained below; the length of this write-up should speak to its simplicity.

Prerequisites

  • WireGuard VPN, configured to handle local address traffic.
  • Linux server (Debian, can be the same machine hosting the WireGuard VPN).
  • Basic command line familiarity.

Initial Setup

On the server meant to host the Vaultwarden instance, install podman and set up the necessary folder structure in your home directory. You will also need to set up a self-signing certificate (acceptable since we are on a VPN). Note that docker is also an option and most guides reference it; I prefer podman since it is more secure by not requiring root access and not having a single point of failure (dockerd).

First, find your server’s IP address. You will need to replace 192.168.1.100 below with your server’s IP address. With the correct IP used, run:

sudo apt update && sudo apt upgrade -y
sudo apt install podman podman-compose git -y
mkdir -p ~/vaultwarden/{data,config,ssl}
cd ~/vaultwarden
echo "ADMIN_TOKEN=$(openssl rand -hex 32)" > .env
chmod 600 .env
openssl req -x509 -newkey rsa:4096 -keyout ssl/private.key -out ssl/certificate.crt -days 36500 -nodes -subj "/CN=192.168.1.100"
chmod 600 ssl/private.key
chmod 644 ssl/certificate.crt

The certificate expires in 100 years (36,500 days). Expiration cannot be disabled completely, but if you have it set for a year your password manager may break and you could waste hours debugging the self-signed certificate you’ve since forgotten about.

You may also need to open the HTTPS port on your firewall if you use UFW. Run sudo ufw status and if it shows as active, run:

sudo ufw allow from 192.168.1.0/24 to any port 8443

Configuration

Still within the ~/vaultwarden folder, create docker-compose.yml by running the following (again, replace 192.168.1.100 with the correct IP address):

cat > docker-compose.yml << 'EOF'
version: '3.8'
services:
  vaultwarden:
    image: docker.io/vaultwarden/server:latest
    container_name: vaultwarden
    restart: unless-stopped
    env_file:
      - .env
    environment:
      WEBSOCKET_ENABLED: 'true'
      SIGNUPS_ALLOWED: 'true'
      DOMAIN: 'https://192.168.1.100:8443'
      ROCKET_TLS: '{certs="/ssl/certificate.crt",key="/ssl/private.key"}'
      LOG_LEVEL: 'warn'
      EXTENDED_LOGGING: 'true'
    volumes:
      - ./data:/data
      - ./ssl:/ssl:ro
    ports:
      - "8443:80"
      - "3012:3012"
EOF

Now run the container and check status:

podman-compose up -d
podman ps

You should see the docker.io/vaultwarden/server:latest container running.

Account Setup

Access the admin console by typing https://192.168.1.100:8443 (replace the IP address) into a browser. You will be prompted to create the username and password, and then download the bitwarden password manager addon. It works perfectly with Vaultwarden and autofills your passwords, so this is highly recommended.

Next, configure it for your self-hosted server when logging in by selecting ‘self-hosted’ at login rather than ‘bitwarden.com’. Use the admin console URL/port again, and log in using the login created earlier.

Automated Start/Restart of Server

The last step here is to ensure Vaultwarden starts back up if the server reboots or has a power failure. This is also very simple to set up by running the following:

systemctl --user enable podman.service
sudo loginctl enable-linger $USER

podman generate systemd --new --name vaultwarden --files
mkdir -p ~/.config/systemd/user
mv container-vaultwarden.service ~/.config/systemd/user/

podman-compose down
systemctl --user daemon-reload
systemctl --user enable container-vaultwarden.service
systemctl --user start container-vaultwarden.service

systemctl --user status container-vaultwarden.service
podman ps

The above code sets up auto-start configuration and generates a systemd file for the vaultwarden service, then brings the Vaultwarden container down to switch over from podman-compose management to systemd management. The last two lines check status; if these look good, you are done.

Conclusion

You should now be able to use Vaultwarden in the browser of your choice. It should (when logged in) prompt you with the option to save passwords, and autopopulate them as needed. I hope this was helpful; if you notice any issues with this guide or process, please feel free to reach out or leave a comment.

My Experiences from NBX and Privacy Hell For Crypto….

nbx-conference

Hello Dev.to Community !

It’s been a while since my recent post on the platform. Today I would like to share with you my experience from NBX (Next Block Expo) event, that was organized in Warsaw, Poland. Although this post will not be filled so much with technical or programming knowledge, I just want to share my view on the conference, from my perspective and couple of thoughts that came into my mind.

Introduction

First, let’s define what Next Block Expo is ? NBX or Next Block Expo is an cryptocurrency-focused event, where all sorts of people from blockchain-technology gather in one place, where there are lectures for newbies or also more advanced market-participants, projects present their product and many more. And by having said all sorts of people, I mean literally ALL SORTS OF PEOPLE, from investors, businessmen/women, CEOs, Journalists, and even politicians through software-devs, people that have no clue what blockchain actually is, scammers, moon-boiz, marketing guys to companies that had their stands at the event.

What companies/projects where at the event ?

It actually needs to be pointed out, that this NBX-edition was combined together with an AI-Summit event, although there were only a couple of companies, having their stands that were focused on AI particularly, and not being an “AI-company” only because they added an tranding OpenClaw-Bot to aid customer’s portfolio.

A lot of the stands were either belonging to B2B-focused companies that help businesses to implement crypto-payments, offering immediate-conversion from crypto to fiat-transfers, off-ramp and on-ramp and this sort of stuff, or exchanges there were BingX, Bybit, ZondaCrypto, Kanga Exchange.

Besides that, what really has thrilled me, is that there were 4 companies or projects that I kept eye on, that were in some-sense delivering or willing to deliver privacy-extending product or they care about privacy.

I will list them out shortly:

  • Relocatify – A company that provides help while opening a bank account in Cambodia and purchase of an real-estate in Cambodia. Why Cambodia is somehow related to privacy ? It’s because they do not have KYC once you want to purchase/sell crypto.

Their financial system is outside of the CRS-system, so they do not report your financial activity. Does it sound like a safe-heaven for criminals ? Well technically yes, but remember criminals were/are/and unfortunately will exist everywhere but will use different methods for their operation.

For me living in EU, where surveillance grows and privacy already seems as a luxury and one needs to fight for it, usually with miserable outcome.

  • Sealed – A private messenger, that is using Falcon as key-signature algorithm, that provides quantum-resistant. It’s still developing and I had an opportunity to test-out the MVP.
    For now it’s going to be supporting only text-messages, but the founders say, that they work on implementing features that support images and documents. The messages will be safely stored on blockchain. The blockchain they are going to use is Algorand.

  • Gen6 – It’s a blockchain that already has it’s collective of Dapps like NCrypt, a private messenger (does not store messages on blockchain and is free to use). There is also RealSeal signs and timestamps your work on-chain. Gen6 Me Identity as an alternative to linktree, but on-chain. And many other products.

  • Neti – A company that is actually all into blockchain and privacy. They are those guys, who can manage everything from tokenization, ZK-Proofs, Privacy tools to Building a Blockchain from ground up. I asked if they have any intern-program and the lady I talked to, has said that it’s limited but they are about to organize hackathons and blockchain-dev community.

My View on freedom and privacy in Europe and Cryptocurrencies in Europe

Although I talked to a lot of cool people from the industry, collected a lot of merch as you can see on the pictures:

Although I talked to a lot of cool people from the industry, collected a lot of merch as you can see on the pictures:

nbx-conference

Then one thing is certain for me. When it comes to Europe, privacy of your financial-matters, does not already exist in Europe. And there is no sign of hope to change this trend, as surveillance will only grow and grow in this region, together with stupid regulations taking away your freedom.

The privacy for cryptocurrencies in Europe is gone, because every for transaction even in ATM or in Exchange-Points, will require from you to go through KYC, which I personally hate and find it only as a part of mass-surveillance.

It’s actually for me disastrous to see, how cryptocurrencies from technology that was about to threaten the entire monetary system and became only an assets or alternative form of payment.

expectations-reality

I think this image explains everything, better than anyone would.

My Personal Experiences

To the event its-self, I’d say I’m disappointed, this time organizers have decided to care more about quantity and not quality of the event, although indeed there were cool projects, this event seemed as a ghost-town for me and the venue was for me not as intuitive as previous one.

The organizers indeed announce a big success, on the event there were more than 2500 people. But the venue for me was a shot in the foot, because of the amount of free space and the actual design of the halls.

Merch-from-nbx

I realized also, there is not so much to learn for me from the panels or lectures, but that’s was obvious to me and tremendously outraged when one of the organizer in the interview said, that those speeches, panels are rather as an add-on and more it’s focused for businesses to be a gateway for new connections and so on.

Is it good ? Is it bad ? I guess as always, depends on the personal perspective. I also did not really like the fact that there has been a separate event for people who speak Ukrainian or Russian.

Don’t get me wrong, I do not have anything against any nation, I don’t care where are you from and what is your skin color, though organizing an separated event solely for certain language-speaking people, this is for a cause that splits people and separates from each other.

Conclusion: I do not like big places e.g. halls and non-technical talks. It was my last NBX-event attended and will look definitely look for technical events or those that are within my field of interest. So cryptography, privacy, blockchain and cybersecurity.

What about you ?

What have you guys been up to recently ? Have you been building some project or have you been doing something else ? Let me know down in the comments and feel free to share your opinion on any part of my article.

Cheers for reading, till next one 😀

I Built a Coordination System for Multiple Claude AI Agents — So They Stop Overwriting Each Other

I Built a Coordination System for Multiple Claude AI Agents — So They Stop Overwriting Each Other

Here’s a problem nobody talks about yet but everyone will hit as AI-assisted development scales up: what happens when two Claude agents are working in the same codebase at the same time?

They overwrite each other. Silently. No warnings, no errors — just lost work.

I built a skill to fix this. It’s called agent-comms, and it gives Claude agents a shared communication channel so they can coordinate before conflicts happen.

The Problem

I’ve been running multiple Claude Code sessions simultaneously on a project — one handling frontend UI work, another fixing the backend pipeline. Both intelligent, both fast, both completely unaware the other exists.

The result: one agent refactors a file, the other overwrites it ten seconds later with a different version. Neither agent knows. The work is gone.

The root issue: Claude agents have no shared awareness. Each terminal is its own isolated context. There’s no built-in coordination layer.

The Solution: File-Based Agent Communication

The only channel multiple Claude agents share is the filesystem. So that’s where I built the communication layer.

agent-comms creates a .agent-comms/ directory in your project root with three JSON files:

.agent-comms/
  registry.json       — who is active right now
  announcements.json  — what files each agent plans to edit (and why)
  messages.json       — direct agent-to-agent messages

A Python script (comms.py) handles all reads and writes — atomic, stale-safe, zero dependencies.

The Protocol

Every agent follows the same lifecycle:

1. Register

python3 $COMMS register researchUI "building dashboard UI components"
python3 $COMMS register Worker1 "fixing backend data pipeline"

2. Announce upfront — before touching any file

python3 $COMMS announce researchUI 
  "src/lib/api.ts|adding stream endpoint" 
  "src/pages/dashboard.tsx|adding real-time chart"

python3 $COMMS announce Worker1 
  "src/lib/api.ts|fixing broken API call" 
  "src/pages/dashboard.tsx|removing hardcoded mock data"

3. Check for conflicts

python3 $COMMS check-conflicts Worker1

Output:

CONFLICT: researchUI also needs src/lib/api.ts — their reason: adding stream endpoint
CONFLICT: researchUI also needs src/pages/dashboard.tsx — their reason: adding real-time chart component

Two conflicts detected. Before a single file was touched.

4. Negotiate

Worker1 (the later announcer) initiates:

python3 $COMMS send Worker1 researchUI 
  "CONFLICT on api.ts — my change: fixing broken endpoint call on line 34. I should go first since it's a bug fix."

python3 $COMMS send Worker1 researchUI 
  "CONFLICT on dashboard.tsx — removing 3 hardcoded mock arrays. Safe to do before your chart work. Suggest: I go first."

researchUI reads and replies:

python3 $COMMS read-messages researchUI
# FROM [Worker1]: CONFLICT on api.ts...
# FROM [Worker1]: CONFLICT on dashboard.tsx...

python3 $COMMS send researchUI Worker1 
  "Agreed — go first on both. I'll wait for your DONE broadcast."

5. Worker1 finishes and broadcasts

python3 $COMMS done Worker1 
  "src/backend/classifier.py" 
  "src/lib/api.ts" 
  "src/pages/dashboard.tsx"

6. researchUI gets the all-clear

python3 $COMMS read-messages researchUI
# FROM [Worker1]: [DONE] Worker1 finished. Modified: src/lib/api.ts, src/pages/dashboard.tsx

researchUI now knows exactly which files were modified and can proceed safely.

Full Terminal Output

Here’s the actual output from a real test run:

=== researchUI announces its files ===
[agent-comms] Announced 3 file(s) for 'researchUI'

=== Worker1 announces its files ===
[agent-comms] Announced 3 file(s) for 'Worker1'

=== researchUI checks for conflicts ===
CONFLICT: Worker1 also needs src/lib/api.ts — their reason: fixing broken API call
CONFLICT: Worker1 also needs src/pages/dashboard.tsx — their reason: removing hardcoded mock data

=== Worker1 negotiates ===
[agent-comms] Sent from 'Worker1' to 'researchUI'
[agent-comms] Sent from 'Worker1' to 'researchUI'

=== researchUI reads messages ===
  FROM [Worker1] @ 2026-03-27T19:14:27: CONFLICT on api.ts — fixing broken endpoint call on line 34. I should go first.
  FROM [Worker1] @ 2026-03-27T19:14:27: CONFLICT on dashboard.tsx — removing 3 hardcoded mocks. Suggest: I go first.

=== researchUI agrees ===
[agent-comms] Sent from 'researchUI' to 'Worker1'

=== Worker1 finishes ===
[agent-comms] 'Worker1' done. Broadcast sent to 1 agent(s).

=== researchUI gets the all-clear ===
  FROM [Worker1]: [DONE] Worker1 finished. Modified: src/backend/classifier.py, src/lib/api.ts, src/pages/dashboard.tsx

=== Final status ===
[agent-comms] Active agents: 1 | Unread messages: 0
  [researchUI] building dashboard UI components
    planned files: dashboard.tsx, Chart.tsx, api.ts

Zero overwrites. Zero lost work.

How It’s Designed as a Claude Code Skill

The system ships as a SKILL.md — a Claude Code skill file that instructs Claude to follow the agent lifecycle automatically. When you invoke superpowers:agent-comms in a Claude Code session, Claude:

  1. Runs status to see who’s active
  2. Auto-assigns itself a name (or asks you to rename it)
  3. Registers itself with its task description
  4. Before any edit session — announces files and checks conflicts
  5. If conflict detected — initiates or responds to negotiation
  6. Every ~10 tool calls — sends a heartbeat
  7. When done — deregisters and broadcasts to all other agents

The SKILL.md protocol:

## Step 2: Announce Upfront (BEFORE any file edit)

Before touching ANY file this session, list every file you plan to edit and why:

python3 $COMMS announce agent-N 
  "path/to/file.ts|reason for editing"

Then immediately check for conflicts:
python3 $COMMS check-conflicts agent-N

If output is CLEAR → proceed.
If output contains CONFLICT → go to Step 3 (negotiation).

Design Decisions

Why file-based?
Claude agents in different terminals share nothing except the filesystem. No sockets, no shared memory, no APIs between them. Files are the only viable channel.

Why upfront announcements instead of locks?
Locks only catch conflicts at the moment of editing — after you’ve already started work. Announcements catch them before any work begins, when the cost of changing course is zero.

Why negotiation instead of blocking?
Blocking wastes time. Negotiation lets agents make intelligent decisions: “include my change,” “I’ll go first,” or “let’s split the file.” The agents have context about what they need — use it.

Stale agent cleanup:
Agents that haven’t sent a heartbeat in 5 minutes are auto-removed from the registry. If an agent crashes without deregistering, it won’t block others indefinitely.

Project-scoped:
.agent-comms/ lives in the project root and is added to .gitignore automatically. Coordination state doesn’t belong in git history.

Install

SKILL_DIR="$HOME/.claude/plugins/cache/claude-plugins-official/superpowers/5.0.5/skills/agent-comms"
mkdir -p "$SKILL_DIR/tests"
curl -o "$SKILL_DIR/comms.py" https://raw.githubusercontent.com/LakshmiSravyaVedantham/agent-comms/main/comms.py
curl -o "$SKILL_DIR/SKILL.md" https://raw.githubusercontent.com/LakshmiSravyaVedantham/agent-comms/main/SKILL.md

Then in any Claude Code session working in a shared project:

superpowers:agent-comms

Tests

19 tests covering the full lifecycle:

python3 -m pytest tests/ -v
# 19 passed in 1.83s

What’s Next

  • Three-agent coordination — tested with 2, curious how negotiation chains work at 3+
  • File section locks — “I own lines 1–80 of this file, you take 81–160”
  • Integration with Claude Code hooks — auto-register/deregister via session hooks

GitHub

github.com/LakshmiSravyaVedantham/agent-comms

Python 3.8+, stdlib only, MIT license. Drop it into your superpowers skill directory and your agents start coordinating immediately.

If you’re running multiple Claude sessions simultaneously, this will save you from the silent overwrite problem sooner or later.

Understanding Attention Mechanisms – Part 2: Comparing Encoder and Decoder Outputs

In the previous article, we explored the main idea of attention and the modifications it requires in an encoder–decoder model. Now, we will explore that idea further.

An encoder–decoder model can be as simple as an embedding layer attached to a single LSTM. If we want a more advanced encoder, we can add additional LSTM cells.

Now, we initialize the long-term and short-term memory in the LSTMs of the encoder with zeros.

If our input sentence, which we want to translate into Spanish, is “Let’s go”, we can feed a 1 for “Let’s” into the embedding layer, unroll the network, and then feed a 1 for “go” into the embedding layer.

This process creates the context vector, which we use to initialize a separate set of LSTM cells in the decoder.

All of the input is compressed into the context vector.

But the idea of attention is that each step in the decoder should have direct access to the inputs.

So, let’s understand how attention connects the inputs to each step of the decoder.

In this example, the first thing attention does is determine how similar the outputs from the encoder LSTMs are to the outputs from the decoder LSTMs at each step.

In other words, we compute a similarity score between the LSTM outputs (the short-term memory or hidden states) from the encoder and the decoder.

For instance, we calculate a similarity score between:

  • The LSTM output from the first step in the encoder, and
  • The LSTM output from the first step in the decoder

We also calculate a similarity score between:

  • The LSTM output from the second step in the encoder, and
  • The LSTM output from the first step in the decoder

There are various ways to calculate this similarity.

One simple method is cosine similarity, which measures how similar two sequences of numbers (representing words) are.

We will explore this further in the next article.

Looking for an easier way to install tools, libraries, or entire repositories?
Try Installerpedia: a community-driven, structured installation platform that lets you install almost anything with minimal hassle and clear, reliable guidance.

Just run:

ipm install repo-name

… and you’re done! 🚀

Installerpedia Screenshot

🔗 Explore Installerpedia here