# ElixirConf EU 2026: Three Technical Shifts That Matter

Estimated read time: 3 minutes

Málaga hosted the ElixirConf EU 2026. Here’s what changed.

1. Type Inference Arrives (No Annotations Required)

Elixir 1.20 introduces whole-program type inference. The compiler now understands function signatures, guard conditions, and map key domains without explicit type annotations.

What this means: A function performing arithmetic on map values now infers that the input must be a map containing numeric keys. Pattern matching across clauses carries type knowledge forward. Handle nil in one branch? Subsequent branches know the value cannot be nil.

The system also tracks map mutations through the Map module, emitting compile-time warnings when operations reference keys proven to be absent.

For teams: Fewer runtime errors. Earlier logic flaw detection. Testing effort shifts from defensive type checking to business logic validation.

Requires Erlang/OTP 27 or later.

2. DurableServer: State That Survives Node Failures

Chris McCord’s keynote introduced DurableServer—a new abstraction for stateful processes that persist across node failures and support seamless state migration in distributed clusters.

The problem it solves: Traditional GenServer implementations tie process state to node lifecycle. Distributed applications struggle with process locality guarantees.

The solution: DurableServer integrates with pluggable storage backends. Process state lives independently of the node.

Complementary sessions demonstrated Kafka-backed architectures and Oban processing at scale. The combination enables architectures that maintain consistency without external coordination layers.

For teams: Redesign stateful components for resilience without rewriting application architecture.

3. Compilation Gets Faster (Up to 4x)

Elixir 1.20 delivers measurable compilation improvements through:

  • Lazy module loading
  • Parallel dependency resolution

Large codebases see build time reductions of up to four times in benchmark scenarios.

Tooling additions:

  • mix source for better visibility
  • Enhanced IEx debugging output
  • Type-aware autocomplete in IEx
  • Improved error messaging for undefined functions

For teams: Lower cognitive overhead when working with large, modular applications.

What This Means for You

Role Implication
Teams evaluating Elixir Enhanced type system reduces test coverage needs for edge cases
Existing Elixir projects Upgrade to 1.20 for incremental type-aware development. Compiler detects redundant clauses and dead code, supporting refactoring with higher confidence
Engineering leadership The “one monolith, many teams” pattern presented at Málaga shows Elixir’s module isolation and supervision trees provide natural boundaries for team autonomy

One More Thing: AI Patterns

Multiple talks addressed AI integration. The BEAM’s lightweight process model aligns naturally with asynchronous, stateful AI orchestration.

Two libraries worth noting:

  • Legion – Code execution by AI agents using pure Elixir
  • Arcana – Retrieval-augmented generation pipelines without external runtimes

Concurrent inference requests. Familiar supervision patterns. No additional orchestration layers.

Sources: ElixirConf EU 2026 announcements, Elixir 1.20 release candidate documentation, and community resources compiled on the Elixir Forum.

Week 1: 100 Days of Solana

Identity on Solana Finally Clicked for Me When I Compared It to SSH Keys

Coming from a Web2 background, I always thought “blockchain identity” sounded way more complicated than it actually is.

People throw around terms like wallets, addresses, private keys, and self-custody, and at first it honestly feels like learning an entirely new internet.

But after spending the past few days working with Solana wallets and keypairs, something finally clicked for me:

A Solana wallet is basically your internet identity backed by cryptography instead of a company database.

And surprisingly, the best analogy I found was SSH keys.

We Already Use This Idea in Web2

If you have ever connected to a remote server using SSH, you already understand the core concept behind Solana identity.

You generate:

  • a public key
  • a private key

You place the public key on the server, and the server trusts you because only you have the matching private key.

No password needs to be repeatedly stored or sent over the network.

That is actually very close to how identity works on Solana.

When you create a Solana wallet, you generate a cryptographic keypair:

  • the public key becomes your wallet address
  • the private key proves ownership

Your wallet address is safe to share publicly. It is basically your on-chain identity.

Something like this:

14grJpemFaf88c8tiVb77W7TYg2W3ir6pfkKz3YjhhZ5

At first glance, it looks random and unreadable, but there is actually a reason for the format.

Solana uses Base58 encoding, which intentionally removes visually confusing characters like:

  • 0 and O
  • I and l

Small detail, but honestly pretty smart.

The Weirdest Part: Nobody Creates Your Account

This was probably the biggest mindset shift for me.

In Web2, every account exists because some company stores it in a database.

Your Gmail account exists because Google says it exists.

Your GitHub username exists because GitHub stores it.

Your bank account exists because a bank manages it.

But on Solana, there is no company creating your identity.

No signup form.
No email verification.
No “forgot password.”

Your identity exists because you generated a keypair.

That is it.

The network simply recognizes cryptographic ownership.

And only whoever controls the private key can approve actions for that wallet.

Ownership Feels Very Different

In Web2, we say we “own” our accounts, but realistically platforms still control access.

Accounts can be:

  • suspended
  • locked
  • recovered
  • deleted

On Solana, ownership works differently.

If you hold the private key, you control the wallet.

Nobody can reset it for you.
Nobody can recover it for you.
Nobody can override your signature.

That freedom is powerful, but it also comes with responsibility.

Losing a password in Web2 is annoying.

Losing a private key in Web3 can mean losing access permanently.

I think that is why people emphasize wallet security so much in crypto. Your wallet is not just an app — it is literally your identity and ownership layer.

One Identity Across Everything

Another thing I found really interesting is how portable blockchain identity becomes.

In Web2, every app wants its own login:

  • username
  • password
  • Google OAuth
  • GitHub OAuth
  • email verification

On Solana, the same wallet can interact across completely different applications.

Once you connect your wallet, apps can recognize:

  • what tokens you own
  • NFTs you hold
  • governance votes
  • transaction history
  • on-chain activity

Without creating another account.

That part honestly feels futuristic compared to the fragmented identity systems we use today.

Identity Becomes Infrastructure

The more I learn about Solana, the more I realize wallets are not just for storing crypto.

They are the foundation for interacting with the network itself.

Your wallet becomes:

  • your login
  • your signature
  • your ownership proof
  • your reputation
  • your access layer

And unlike traditional platforms, it works across the entire ecosystem instead of being trapped inside one company’s database.

That was the moment blockchain identity finally started making sense to me.

Not as “magic internet crypto stuff,” but as a completely different model for proving ownership and trust online.

MLH Challenge: [# Identity on Solana Finally Clicked for Me When I Compared It to SSH Keys

Coming from a Web2 background, I always thought “blockchain identity” sounded way more complicated than it actually is.

People throw around terms like wallets, addresses, private keys, and self-custody, and at first it honestly feels like learning an entirely new internet.

But after spending the past few days working with Solana wallets and keypairs, something finally clicked for me:

A Solana wallet is basically your internet identity backed by cryptography instead of a company database.

And surprisingly, the best analogy I found was SSH keys.

We Already Use This Idea in Web2

If you have ever connected to a remote server using SSH, you already understand the core concept behind Solana identity.

You generate:

  • a public key
  • a private key

You place the public key on the server, and the server trusts you because only you have the matching private key.

No password needs to be repeatedly stored or sent over the network.

That is actually very close to how identity works on Solana.

When you create a Solana wallet, you generate a cryptographic keypair:

  • the public key becomes your wallet address
  • the private key proves ownership

Your wallet address is safe to share publicly. It is basically your on-chain identity.

Something like this:

14grJpemFaf88c8tiVb77W7TYg2W3ir6pfkKz3YjhhZ5

At first glance, it looks random and unreadable, but there is actually a reason for the format.

Solana uses Base58 encoding, which intentionally removes visually confusing characters like:

  • 0 and O
  • I and l

Small detail, but honestly pretty smart.

The Weirdest Part: Nobody Creates Your Account

This was probably the biggest mindset shift for me.

In Web2, every account exists because some company stores it in a database.

Your Gmail account exists because Google says it exists.

Your GitHub username exists because GitHub stores it.

Your bank account exists because a bank manages it.

But on Solana, there is no company creating your identity.

No signup form.
No email verification.
No “forgot password.”

Your identity exists because you generated a keypair.

That is it.

The network simply recognizes cryptographic ownership.

And only whoever controls the private key can approve actions for that wallet.

Ownership Feels Very Different

In Web2, we say we “own” our accounts, but realistically platforms still control access.

Accounts can be:

  • suspended
  • locked
  • recovered
  • deleted

On Solana, ownership works differently.

If you hold the private key, you control the wallet.

Nobody can reset it for you.
Nobody can recover it for you.
Nobody can override your signature.

That freedom is powerful, but it also comes with responsibility.

Losing a password in Web2 is annoying.

Losing a private key in Web3 can mean losing access permanently.

I think that is why people emphasize wallet security so much in crypto. Your wallet is not just an app — it is literally your identity and ownership layer.

One Identity Across Everything

Another thing I found really interesting is how portable blockchain identity becomes.

In Web2, every app wants its own login:

  • username
  • password
  • Google OAuth
  • GitHub OAuth
  • email verification

On Solana, the same wallet can interact across completely different applications.

Once you connect your wallet, apps can recognize:

  • what tokens you own
  • NFTs you hold
  • governance votes
  • transaction history
  • on-chain activity

Without creating another account.

That part honestly feels futuristic compared to the fragmented identity systems we use today.

Identity Becomes Infrastructure

The more I learn about Solana, the more I realize wallets are not just for storing crypto.

They are the foundation for interacting with the network itself.

Your wallet becomes:

  • your login
  • your signature
  • your ownership proof
  • your reputation
  • your access layer

And unlike traditional platforms, it works across the entire ecosystem instead of being trapped inside one company’s database.

That was the moment blockchain identity finally started making sense to me.

Not as “magic internet crypto stuff,” but as a completely different model for proving ownership and trust online.

MLH Challenge: [https://www.mlh.com/events/100-days-of-solana/challenges]

How I built an anonymous daily leaderboard — and why it resets every night

Every competitive typing site has a leaderboard. Most of them are terrible.

TypeRacer shows you an all-time WPM rank that you’ll never crack. MonkeyType has a global top-1000 that’s been locked in by dedicated grinders for years. Both create the same problem: if you’re not already in the top tier, the leaderboard is demotivating noise.

When I built Clackpit, I wanted a leaderboard that actually worked for a normal person sitting down to practice. That meant rethinking two things: identity and time horizon.

The problem with persistent identity

Most leaderboards require an account. Name, email, password — the whole thing. That’s fine for a product where you’ve already committed to the user relationship. But for a typing site, where someone might show up for a 3-minute race and never return, it’s a massive conversion blocker.

I wanted anyone to be competitive immediately. No friction.

The solution I landed on: anonymous handles that persist in localStorage, chosen from a curated wordlist on first visit.

const ADJECTIVES = ['swift', 'nimble', 'sharp', 'quick', 'bright', /* ... */];
const NOUNS = ['falcon', 'arrow', 'spark', 'dash', 'flare', /* ... */];

function generateHandle(): string {
  const adj = ADJECTIVES[Math.floor(Math.random() * ADJECTIVES.length)];
  const noun = NOUNS[Math.floor(Math.random() * NOUNS.length)];
  const num = Math.floor(Math.random() * 99) + 1;
  return `${adj}${noun}${num}`;
}

// Store in localStorage so it persists across sessions
function getOrCreateHandle(): string {
  const stored = localStorage.getItem('clackpit_handle');
  if (stored) return stored;
  const handle = generateHandle();
  localStorage.setItem('clackpit_handle', handle);
  return handle;
}

The handle is sticky — come back tomorrow and you’re still swiftfalcon42. You can change it, but you don’t have to. It’s yours without signing up.

The problem with all-time leaderboards

Persistent leaderboards have a nasty property: they compound. The longer they exist, the more locked-in the top positions become. A new user who types 90 WPM sees a leaderboard full of 140+ WPM monsters and correctly concludes that competing is pointless.

The fix is surprisingly simple: reset the leaderboard every night at midnight UTC.

A daily leaderboard has a completely different social dynamic:

  • Everyone starts equal each day. The person who showed up for the first time today can be #1 by the end of the day.
  • Yesterday’s champion is gone. That 140 WPM monster? They have to earn it back.
  • Streaks become the real achievement. Staying in the top 10 for a week is more interesting than a stale number on a permanent board.

The implementation

I’m running on Cloudflare Workers with KV storage. The leaderboard is a sorted list stored in KV with a TTL that expires at the next midnight UTC.

// Calculate seconds until next midnight UTC
function secondsUntilMidnightUTC(): number {
  const now = new Date();
  const midnight = new Date(now);
  midnight.setUTCHours(24, 0, 0, 0);
  return Math.floor((midnight.getTime() - now.getTime()) / 1000);
}

async function submitScore(
  kv: KVNamespace,
  handle: string,
  wpm: number,
  accuracy: number
): Promise<void> {
  const key = 'leaderboard:daily';
  const ttl = secondsUntilMidnightUTC();

  const raw = await kv.get(key);
  const entries: LeaderboardEntry[] = raw ? JSON.parse(raw) : [];

  // Update or insert this handle's best score
  const existing = entries.findIndex(e => e.handle === handle);
  if (existing >= 0) {
    if (wpm > entries[existing].wpm) {
      entries[existing] = { handle, wpm, accuracy, ts: Date.now() };
    }
  } else {
    entries.push({ handle, wpm, accuracy, ts: Date.now() });
  }

  // Keep top 100, sorted by WPM descending
  entries.sort((a, b) => b.wpm - a.wpm);
  const top100 = entries.slice(0, 100);

  await kv.put(key, JSON.stringify(top100), { expirationTtl: ttl });
}

The TTL does the reset automatically. No cron job, no cleanup task. When the KV key expires, the leaderboard is gone. Next write creates a new one that expires at the next midnight.

What I learned

The daily reset changes behavior in ways I didn’t predict.

I expected it to just be “fairer.” What I didn’t expect was that it makes people check back more often. If you posted a 95 WPM score and there are 3 hours left in the day, you have a reason to come back tomorrow and see if you held on. If the leaderboard were permanent, there’s no urgency.

Anonymous handles have a surprising amount of personality. quietarrow71 feels different from swiftfalcon42. People started identifying with their handles even without accounts.

The all-time leaderboard problem is worse than I thought. After watching a few users interact with the board, I noticed that the first thing most people do is scroll to find where they rank. On a daily board, everyone is visible (it only has today’s players). On a permanent board, most newcomers wouldn’t appear at all. That invisibility is demoralizing.

If you want to see it in action: Clackpit. Sprint mode submits to the daily board after your race. Try it and see where you land before midnight resets it.

Curious what others have done for leaderboards — permanent, daily, weekly? Drop your approach in the comments.

Lessons from three months of vibe coding (and a complexity score of 53)

TL;DR — I spent three months vibe-coding a side project with an AI agent. It felt fast and productive until I opened a file and saw 3000 lines, functions that should have been one helper but were copy-pasted ten times, and a cyclomatic complexity score of 58 in one of them. The agent wasn’t the problem. The missing feedback loop was. This is what I should have set up on day one — and what I now consider non-negotiable when working with AI agents.

uv run complexipy . --top 10
./rounds/views.py
    current_state 58 (last: 52, Δ = +6)  ❌ FAILED
    host_advance_post_round 45 (last: 9, Δ = +36)  ❌ FAILED
    host_rewind_round 37 (new, Δ = +37)  ❌ FAILED
    audience_panel 34 (last: 35, Δ = -1)  ❌ FAILED
    debate_vote_results 18  ❌ FAILED
    host_create_game 16  ❌ FAILED
    _debate_winner_details 12  ✅ PASSED
    audience_prompt_submitted 11  ✅ PASSED
    host_select_vote_winner 11  ✅ PASSED
    preview_screen 11  ✅ PASSED

Failed functions:
 - ./rounds/views.py: audience_panel, current_state, debate_vote_results, host_advance_post_round, host_create_game,
host_rewind_round

The moment it clicked

I wasn’t running a tool. I wasn’t reviewing a PR. I was just poking around the repo to remind myself where something lived, and I opened a file that had grown past 3000 lines.

Inside, I found functions that should have been one shared helper, copy-pasted with one or two lines different each time. Every time I’d asked the agent to add a feature that was “similar but slightly different,” it had just duplicated the whole thing and tweaked the bits that varied.

I ran radon out of curiosity. One function clocked in at cyclomatic complexity 58. Fifty-three branches in a single function. That was the moment I realized I had a problem I couldn’t easily fix.

How I got there

I want to be honest about how this started, because I think it’s the most common path.

It was a small idea — a Django side project. I knew how to code; this wasn’t me learning Python from scratch. But I was learning how to work with an AI agent. I didn’t know the workflows, the tooling around agents, what good guardrails looked like, or how other people were structuring this kind of work. So I was figuring it out as I went.

I told myself I was doing spec-driven development. I’d write a description of what I wanted, hand it to the agent, and review the output. In reality, I was vibe coding. I wasn’t actually reading the diffs. I was checking that the feature worked — does the endpoint return the right thing? does the test pass? — and moving on. The agent shipped, I accepted, repeat.

For weeks it felt great. Features landed. Tests were green. I had momentum.

The slow collapse

The problem wasn’t a single bad commit. The problem was a thousand small, locally rational choices.

Every time I asked for a feature that was “like the last one but with a small change,” the agent didn’t extract a shared helper — it copied the previous implementation and edited it. That’s the safest move for the agent in any given turn: copying working code is less likely to break than refactoring. Without anything pushing back, copying wins every time.

The if/elif chains kept growing. New cases got appended, not refactored into a dispatch table or a strategy. Branches piled on branches. One function ended up at CC 58.

The CSS — same story. New components got their own styles, copy-pasted from the previous component, slightly tweaked. There was no design system, no shared tokens, no enforced layering. It just sprawled.

By the time I noticed, two things were true at once:

  1. The codebase was big enough that I couldn’t hold it in my head anymore.
  2. I was afraid to touch it myself. Not because I didn’t know how — because any change risked breaking something I couldn’t reason about. The agent had become the only entity that could navigate the mess, and it was the one that had created the mess.

That’s the worst place to be. The point of using an AI agent is to amplify what you can do. If you end up unable to refactor your own code without the agent, you haven’t amplified anything. You’ve outsourced something you can’t take back.

The actual lesson

Here’s what I missed: the agent has no perception of whether code is good or bad. None. It doesn’t know your conventions, your architecture, your standards. It doesn’t get tired. It doesn’t refactor unless something tells it to.

I thought I was giving it feedback. I wasn’t. “Make it cleaner” is not feedback an agent can act on. “Reduce complexity” is not feedback either. The agent needs feedback that is specific, machine-readable, and automatic — the kind you get from a linter, a type checker, an architectural test.

When I had no feedback loop, the agent did exactly what an unsupervised junior dev would do under pressure: it solved each problem in the easiest local way. Copy-paste. Append a branch. Skip the refactor. Each move was rational on its own. The aggregate was slop.

The reframe that finally landed for me: the agent behaved correctly given the environment I gave it. The environment was the bug, not the agent.

Why quality gates are non-negotiable now

Quality gates — linters, type checks, complexity limits, architectural fitness functions, duplication detectors — were a “good engineering practice” before AI. They were nice to have. You could ship without them.

With AI-assisted development, that changes. Here’s why:

  • The rate of code production is now far higher than your rate of code comprehension. Your mental context window didn’t grow when you started using an agent. The codebase’s growth rate did.
  • The agent has no memory of your conventions across sessions. Anything you don’t encode in tooling will drift.
  • The agent has no incentive to refactor. Refactoring increases diff size and risk. Copying is cheaper. Without a gate, entropy wins.
  • “Just review it carefully” doesn’t scale. That defeats the entire point of using an agent. If every diff needs a human read for style and complexity, you’ve lost the speedup.

So gates aren’t optional anymore. They’re prerequisites. You set them up before the agent writes a line, not after. The time you spend configuring them up front is the rule of our job now — it’s not overhead, it’s the work.

Matt Pocock frames this as “outrunning your headlights”: AI generates code faster than you can verify it, and the only way to stay inside the beam is the same discipline that always kept engineers honest — incremental delivery, test-first, and structures you can reason about. The gates are what put the headlights back on.

When the agent produces something that violates a gate, the failure is automatic, specific, and machine-readable. You feed it back to the agent, the agent fixes it, you move on. That is the feedback loop I was missing for three months.

The checklist I wish I’d had on day one

I’m building this in tiers. Pick the tier that matches the project’s lifespan.

Tier 0 — Bare minimum (any project, even a weekend hack)

Set up before the agent writes a single line.

  • pyproject.toml with ruff for lint + format. Enable complexity rules (C901, max-complexity around 10), bugbear (B), simplify (SIM), pyupgrade (UP), and a sensible subset of pylint (PL).
  • Strict type checking with mypy or pyright in strict mode for your own modules.
  • Pre-commit hooks wired to both, so violations can’t even land in a commit.
  • A task runner like mise (or a Makefile / justfile) with check, test, fix tasks. One obvious command for the agent to run.
  • A short CONTRIBUTING.md, AGENTS.md, or .cursorrules stating: max function length, max complexity, layering rules (router → service → repository), no business logic in routers, no SQL outside repositories, no copy-paste — extract a function or ask.
  • A skill library that encodes your architecture decisions as agent-readable workflows, not just rules. Rules tell the agent what not to do; skills tell it what to reach for. superpowers, get-shit-done, and mattpocock/skills are good starting points — or write framework-specific ones: “when building a FastAPI endpoint, always layer router → use case → repository, never skip levels.”

Tier 1 — Recommended for anything you’ll touch in a month

  • pytest with coverage gated at a real number (60–80%, not 100%).
  • A duplication detector (pylint --enable=duplicate-code, or jscpd).
  • bandit for security smells.
  • CI that runs all of this on every PR and blocks merge.
  • A single integration test that boots the app and hits /health. This alone catches most “the agent broke imports” failures.

Tier 2 — Production-grade

  • Architectural tests — Python lets anything import anything; you need to enforce lanes explicitly. Three options depending on taste: import-linter (contract-based, closest to config), pytest-archon (same idea expressed as pytest tests — easier for complex rules), deply (layer-based, closer to ArchUnit if you’re coming from Java). Good writeups: roman.pt, dev.to/vashkatsi.
  • Mutation testing on critical modules (mutmut). Agents love writing tests that pass without testing anything.
  • Dependency scanning (pip-audit).
  • Complexity tracked over time with radon or xenon in CI — fail on regressions, not just absolute thresholds.
  • Contract tests against your OpenAPI spec (schemathesis). Free coverage given you’re on FastAPI.

How to give the agent useful feedback

This is the part that changed my workflow most.

Don’t say: “this code is messy, clean it up.”
Do say: “here is the output of ruff check app/services/user_service.py. Fix every finding without using # noqa. If a fix changes a function signature, list the call sites first and propose the change.”

Don’t say: “reduce complexity.”
Do say: “this function dispatches on event_type with a 58-branch if/elif chain. Replace it with a dict mapping event_type to handler functions, one handler per branch, each unit-tested.”

The pattern: specific, mechanical, verifiable. Name the refactor. Cite the tool output. Constrain the solution. That’s how you get a refactor instead of a rename.

The tooling in my reference project

After the Django project, I started a separate FastAPI reference project specifically to encode what I’d learned. Different framework, but the principles are framework-agnostic. The point isn’t FastAPI vs. Django — the point is what the setup looks like before any feature code lands.

You can find it here: github.com/maxkrivich/fast-api-reference-project

A quick note before the tool list: you don’t need enterprise tooling for this. SonarQube, Codacy, Snyk, and if your company already pays for them, use them. But every gate I’m about to list is open source and free, and the entire point — feeding structured failures back to an agent — works just as well with ruff and mypy as it does with a commercial SaaS. Don’t let “we don’t have SonarQube” be the reason you skip the gates.

Here’s what’s in the repo, briefly:

  • ruff — single tool for lint + format, fast enough to run on save. Complexity is gated at max-complexity = 10 — a threshold that would have caught my CC=58 immediately. Config lives in ruff.toml.
  • ty in strict mode — Astral’s new type checker. Catches a huge class of agent mistakes (wrong types, missing returns, unhandled Optional) before they reach runtime.
  • prek — Rust-based git hooks manager (same idea as pre-commit, but faster and no Python dependency). Runs ruff, bandit, import-linter, pylint, gitleaks, and hadolint on every commit. Config in prek.toml.
  • mise — one entry point for tasks and tool versions. The agent runs a single command (mise run full-ci-check) and gets a structured report it can act on. Config in mise.toml.
  • pytest + coverage — the baseline. Gated at a real number, not aspirational.
  • bandit — security smells. Catches agent moves like subprocess.run(..., shell=True) with user input.
  • pip-audit — dependency CVEs, run as uv audit in CI. Agents will happily pin a vulnerable version if you don’t check.
  • import-linter — enforces hexagonal architecture via import contracts. Seven contracts defined in pyproject.toml that make the build fail if a router imports a SQLAlchemy session directly, or a domain model touches an HTTP adapter. Python lets anything import anything — this is how you enforce the lanes.
  • pylint (duplicate-code only) — runs on every commit via prek, flagging copy-paste before it accumulates. The exact failure mode that wrecked my Django project.
  • radon / xenon — complexity tracking. In dev deps for local inspection; the plan is to wire xenon into CI to fail on regressions, not just absolute thresholds.
  • CI via GitHub Actions — every PR runs the full gate set; nothing merges that hasn’t passed. Workflows live in .github/workflows/.

What gates won’t catch

Honest disclaimer, because I don’t want to oversell this.

Gates catch mechanical slop — complexity, duplication, style, types, surface-level security. They don’t catch architectural slop — wrong abstractions, leaky boundaries, anemic domain models, a service that should have been three services. They don’t catch a bad data model. They don’t catch a missing concept.

What gates do is reclaim your attention. Once mechanical quality is automated, your code reviews shift from “is this clean?” to “is this the right shape?” That’s a much better use of human attention, and it’s the only kind of review that’s actually worth your time when working with an agent.

You still have to think. The gates just stop you from drowning while you do it.

Where I’m at now

The project that hit CC 58 is at a point where I think it’s easier to rewrite than refactor. That’s a hard thing to admit, but it’s where I am. The next version starts with the checklist in place before any feature lands.

If there’s one thing I’d want you to take from this: set up the gates first. Not after the first feature. Not after the first refactor. First. The hour you spend configuring ruff and pre-commit on day one is the hour that prevents the month you’d otherwise spend untangling slop on day ninety.

The agent is not the problem. The environment we give it is.

If you’ve been through something similar, or have tooling I missed, I’d genuinely like to hear it — leave a comment or ping me on GitHub.

30 CVR Improvement Checks for EC Sites — Where to Start When Sales Don’t Move

30 CVR checks across 6 areas

“Ad sessions keep coming in, but purchases are not growing.” “Add-to-cart looks fine, but checkout drops off.” Every EC operator hits this wall, and the answer is almost always the same one — a CVR (Conversion Rate) leak somewhere in the funnel.

CVR is a simple formula — purchasing sessions ÷ all sessions — but the levers that move it are scattered across 30+ tactics, and the order you fix them in matters more than the list itself. If you start from the bottom of the impact curve, you spend three weeks on a banner test that moves nothing.

This post organizes the most common CVR improvement levers into 6 areas × 5 items = 30 checks, sorted by impact range and engineering effort. Fix them top to bottom and you fix the ones that move revenue first.

TL;DR

  • CVR improvement levers fit into 6 areas: Tech, UX, Trust, Pricing, Cart & Checkout, Personalization. Each area has a different impact range and effort cost.
  • The order to fix them in is the top-left of an Impact × Effort 4-quadrant map: LCP, cart save, shipping disclosure, form minimization — 8 items in the high-impact × low-effort quadrant move roughly half of the available revenue.
  • Chasing CVR alone is a trap: aggressive couponing lifts CVR but drops AOV and gross margin. Watching CVR, AOV, and RPS (Revenue Per Session) together is the safer view.

The big picture — where in the funnel does CVR actually leak

CVR is one of the three components of the revenue decomposition formula:

Revenue = Sessions × CVR × AOV

If sessions stay flat and CVR moves from 1.5% to 2.0%, revenue grows by roughly 33% with zero extra ad spend. That is why CVR improvement is one of the highest-ROI levers in EC operations.

CVR itself is not a single number — it is the product of pass-through rates at each funnel stage:

  • Product Detail Page (PDP) view rate
  • Add-to-cart rate
  • Checkout initiation rate
  • Purchase completion rate

Identifying which stage is leaking — using GA4 funnel reports, or a real-time visitor feed — narrows the candidate fixes dramatically before you spend any engineering time.

Here is the full 6-area × 5-item map at a glance.

30 CVR checks across 6 areas

Tech area — speed and errors quietly bleed CVR

The Tech area is the foundation. If Core Web Vitals are broken, every UX and pricing improvement on top of it leaks into the void.

  1. LCP (Largest Contentful Paint) under 2.5s — the largest above-the-fold element (usually the hero image or product image) needs to paint fast.
  2. CLS (Cumulative Layout Shift) under 0.1 — buttons that shift during load cause misclicks and silent abandonment.
  3. 404 monitoring — old SKUs and retired URLs hit from newsletters and ad creatives drop into 404 land.
  4. Mobile layout regressions — weekly QA across iOS Safari, Android Chrome on the form and the buy button.
  5. HTTPS and mixed content — leftover http:// references in images or iframes break the lock icon.

Out of these five, the highest-leverage one is LCP improvement. The rough field heuristic among EC operators is that moving LCP from 4s to 2s lifts CVR by about 5–15%.

UX area — forms and navigation are the real abandonment drivers

If product intent is high but purchases are not landing, the leak is almost always in the UX area.

  1. Checkout form fields ≤ 8 — strip to address, name, phone, card.
  2. Guest checkout available — forcing account creation kills CVR by 20–30%.
  3. CTA button color and label — clear contrast and unambiguous labels (Add to Cart, Checkout).
  4. Search bar accuracy — handle typos and product name variants.
  5. Mobile scroll depth on PDP — the add-to-cart button needs to be visible without long scrolling.

The standout here is opening guest checkout. Effort is small, CVR impact is large. According to Baymard Institute‘s cart abandonment research, “had to create an account” sits in the top reasons for cart abandonment year after year.

Trust × Pricing × Cart — 15 checks that hold the “just about to buy” moment

Users with intent get pushed back at the last step by three areas — trust, pricing, and the cart/checkout flow itself.

Trust area (5 checks)

  1. Shipping cost and ETA shown up-front — discovering shipping cost only at the cart is the single most cited cart abandonment cause.
  2. Returns and refund policy reachable in 1 click from PDP.
  3. Review count and star rating displayed at the top of PDP.
  4. SSL mark and payment logos — Visa, Mastercard, PayPay, Amazon Pay logos signal accepted methods.
  5. Contact path — chat or phone number in both the footer and PDP.

Pricing & promotion area (5 checks)

  1. Compare-at price — show MSRP vs sale price, or a one-line market reference.
  2. Free-shipping threshold hint — “¥X away from free shipping” on the cart.
  3. Coupon clarity — never spring a coupon field at the last checkout step.
  4. Out-of-stock alternatives — recommend same-category items when stock is zero.
  5. Restraint on flash-sale urgency — overdone urgency actually drops CVR.

Cart & checkout area (5 checks)

  1. Persistent cart — hold cart contents for 7+ days without login.
  2. Multiple payment methods — at least 3 of card, conbini, PayPay, Amazon Pay, BNPL.
  3. Postal code auto-fill for address input.
  4. Numeric keyboard invoked for card number on mobile.
  5. Specific error messages — Please check the card number length beats Card number is invalid.

Out of these 15, the three with the strongest cost-to-impact ratio are persistent cart × shipping disclosure × free-shipping threshold. The effort is roughly one engineering day combined, and the CVR lift typically clears single-digit percent.

Personalization — the last nudge, built into the system

The final push toward conversion comes from showing each visitor something different based on their context.

  1. PDP recommendations based on browsing history.
  2. Cart abandonment recovery email within 24 hours, one message.
  3. Exit-intent popup — trigger free-shipping messaging when the mouse moves toward the browser chrome.
  4. Loyalty perks surfaced to returning visitors.
  5. Live chat triggered right before exit.

Now that all 30 items are on the table, the impact range × effort 4-quadrant map below shows where to start. The 8 items in the top-left (high impact × low effort) move roughly half of the available revenue first.

CVR improvement: Impact × Effort 4-quadrant map (1-30 numbered)

After all 30 checks are addressed, the CVR ceiling on the site itself starts to show.

The “CVR-only” trap, and watching revenue instead

Going through all 30 checks will lift CVR — but the revenue lift tends to come in smaller than expected. The reason is that some CVR-lifting moves quietly drop AOV.

A “20% off site-wide coupon” lifts CVR in the moment, but AOV and gross margin drop in parallel. Plugging it back into Revenue = Sessions × CVR × AOV, revenue moves up slightly while gross profit goes down. CVR is a great metric to chase, but only when watched alongside AOV.

I’m building a tool called RevenueScope that watches CVR, AOV, and RPS (Revenue Per Session) on one screen, broken down by channel. GA4 measures the traffic side beautifully but requires hopping across reports to get to CVR — RevenueScope approaches it from the revenue side first and reads back to the channel, so the impact of each of these 30 checks shows up as “which channel moved how much in revenue” instead of “which page moved in CVR alone”.

“Fix all 30 CVR checks” is step one. Step two — verifying that the fixes moved revenue, not just CVR — is the part that protects you from the coupon trap.

Related posts on the same series:

References

  1. Google Web.dev — Core Web Vitals (May 2026)
  2. Baymard Institute — 46 Cart Abandonment Rate Statistics 2024 (2024)

What is the one check on your own site you have been postponing the longest? Mine was guest checkout for too long. Curious whether the Tech-first ordering (LCP before everything else) matches what other operators are seeing, or if you start from UX/forms — drop a note below.

Which Tech Roles Will Dominate Vietnam’s IT Industry in the Next Few Years?

Vietnam’s IT Market Feels Like It’s Entering A Different Era

Over the past few months, I’ve been seeing more and more discussions around salaries, hiring trends and career directions in Vietnam’s tech industry. And honestly, the market feels very different compared to just a few years ago.
Back then, the “safe route” usually meant:

  • frontend/backend development

  • mobile engineering

  • fullstack paths

  • climbing toward senior developer or tech lead

But recently the conversation has shifted heavily toward:

  • AI Engineering

  • MLOps

  • Data Engineering

  • GenAI integration

  • AI-assisted workflows

At the same time, many developers are also starting to question whether traditional web/app development is becoming oversaturated.

A Vietnam IT Salary Guide I Found Surprisingly Insightful

Out of curiosity, I looked through this: https://www.jt1.vn/salaryguide

A few insights from it were surprisingly interesting. The biggest thing that stood out was how AI/ML-related roles are currently among the highest-paid positions in Vietnam’s IT market.

According to the guide, engineers with AI/ML, MLOps and GenAI integration skills are earning noticeably higher compensation compared to many traditional engineering positions.

The report also mentioned something called the “Trust Paradox” in AI development: developers increasingly use AI tools for speed and productivity but still don’t fully trust the outputs generated by AI systems. That idea honestly feels very real right now.

Developers May Be Shifting From “Coding” to “Supervising AI”

With tools like Copilot, Cursor, GPT-based workflows, and AI agents becoming more common, it feels like developers are slowly moving toward a different role. Not necessarily replacing engineers but changing what engineers actually do.

Instead of writing every line manually and solving everything from zero, developers may spend more time: reviewing AI-generated outputs, debugging generated code, designing architecture, validating business logic and orchestrating systems.

So What Will Actually Dominate The Next Few Years?

That’s the part I’m curious about. Right now AI/ML looks incredibly hot, especially in terms of salary growth and hiring trends, but tech changes insanely fast.

A few years ago everyone was talking about blockchain, Web3, crypto and metaverse. Now the conversation is completely different again.
So I’m wondering do you think AI/ML-related roles will truly dominate the next phase of the industry, or will another field/position become the next major wave in tech?

Would love to hear perspectives from people already working in different areas of the industry.

LLM Wiki – Compiled Knowledge That RAG Cannot Replace

The premise is simple: compiled knowledge is more reusable than retrieved fragments.
RAG became the default answer to a straightforward question – how do I give an LLM access to external knowledge?

And the usual architecture is by now familiar.
Take documents, split them into chunks, embed the chunks, store them in a vector database, retrieve relevant pieces at query time, and pass them into the model. That pattern is useful, but it is also overused. RAG is very good at access and not automatically good at structure. It can find relevant fragments but does not create a stable understanding of a domain, it can retrieve context but does not decide what the canonical explanation is, and it can answer from documents but does not maintain a living knowledge base.

LLM Wiki is not just another retrieval pattern but a different way to think about knowledge architecture entirely. Instead of asking the model to synthesize from raw chunks every time a question is asked, an LLM Wiki uses the model earlier in the pipeline, performing synthesis at ingest time and storing the result as structured, readable, linked knowledge.

A good shorthand is this:

  • RAG retrieves knowledge at query time.
  • LLM Wiki compiles knowledge at ingest time.

That distinction changes cost, latency, quality, maintenance, governance, and failure modes – and it is the central reason LLM Wiki deserves its own architecture category.

RAG optimizes retrieval, not representation

RAG is powerful because it lets a language model use information outside its training data, making it useful for:

  • company documentation
  • product manuals
  • technical support
  • internal search
  • research assistants
  • policy lookup
  • code documentation
  • knowledge base chatbots

But RAG has a structural weakness: it often treats knowledge as a pile of retrievable fragments rather than a structured model of a domain.

A typical RAG system works like this:

  1. Collect documents.
  2. Split them into chunks.
  3. Create embeddings.
  4. Store the chunks in a vector database.
  5. Retrieve similar chunks for each query.
  6. Ask the LLM to answer using those chunks.

This works well for many questions, but it also creates repeated interpretation work for complex ones. Every time a user asks something conceptually rich, the system has to:

  • retrieve fragments
  • decide which fragments matter
  • infer relationships
  • resolve contradictions
  • build a temporary explanation
  • produce an answer

Then that synthesis disappears and the next query starts from scratch. This is fine when questions are simple, but it becomes wasteful when the same concepts are repeatedly reconstructed from raw fragments.

The most common RAG mistake is assuming that better retrieval equals better knowledge. Sometimes that is true, but often it is not, because retrieval and representation solve different problems. Retrieval answers which pieces of text are relevant; representation answers how knowledge should be structured in the first place. A RAG system can retrieve five accurate chunks about a topic and still fail because:

  • the chunks are outdated
  • the documents contradict each other
  • the important concept is spread across pages
  • the source uses inconsistent terminology
  • the answer requires synthesis, not lookup
  • there is no canonical page

RAG is an access layer, not a knowledge model by itself, and an LLM Wiki exists precisely because some knowledge should be represented before it is retrieved.

What is an LLM Wiki?

An LLM Wiki is a knowledge system where a language model helps transform source material into structured wiki-like knowledge. Instead of storing only raw documents and retrieving chunks later, the system creates derived knowledge artifacts such as:

  • topic pages
  • summaries
  • glossaries
  • concept pages
  • entity pages
  • cross-links
  • comparisons
  • contradiction notes
  • source references
  • decision records
  • explanations

The output is usually human-readable and, in many implementations, stored as plain Markdown, which matters because Markdown makes the system:

  • inspectable
  • portable
  • editable
  • versionable
  • easy to diff
  • compatible with static sites and PKM tools

The idea is not that the LLM magically knows everything but that the LLM helps maintain a structured layer over the source material, acting as a structuring assistant rather than the final authority.

The core idea

The core idea of LLM Wiki is ingest-time knowledge synthesis. In a RAG system, synthesis usually happens when a user asks a question; in an LLM Wiki, synthesis happens earlier, during ingestion, before any question has been asked.

A simplified pipeline looks like this:

sources
  -> ingest
  -> summarize
  -> structure
  -> link
  -> maintain
  -> query or browse

The system does not wait until query time to figure out what the knowledge means – it creates a reusable structure in advance, which makes LLM Wiki closer to a compiled knowledge base than a search pipeline.

A practical example

Imagine you have 60 articles about local LLM hosting. A RAG system might split them into chunks and retrieve relevant sections when you ask about the differences between Ollama, vLLM, llama.cpp, and SGLang, then let the LLM assemble an answer from those retrieved fragments.

An LLM Wiki system does something different. At ingest time, it creates structured pages:

  • ollama.md
  • vllm.md
  • llama-cpp.md
  • sglang.md
  • local-llm-hosting-overview.md
  • inference-backends-comparison.md
  • gpu-memory-and-context-length.md

Then it links them. When you later ask a question, the system is not starting from raw fragments but from a structured knowledge layer that was already assembled before the question arrived – and for conceptual and comparative questions, that difference in quality is significant.

How LLM Wiki works

There is no single official implementation, but most LLM Wiki systems follow the same conceptual stages.

Source collection

The system starts with source material – blog posts, PDFs, Markdown notes, technical documentation, transcripts, papers, meeting notes, bookmarks, code comments, and README files – which should be preserved as a separate layer, distinct from the generated wiki. This matters because generated wiki pages are derived knowledge, not original truth, and a serious LLM Wiki should always maintain links back to sources so that every generated page can answer the basic question: where did this claim come from?

Ingestion and extraction

During ingestion, the system reads source material and extracts useful knowledge. It may identify:

  • main topics
  • entities and tools
  • definitions
  • claims
  • decisions
  • examples
  • contradictions between sources
  • open questions
  • recurring concepts

This stage is where LLM Wiki starts to differ from ordinary RAG: while RAG usually chunks documents for retrieval, LLM Wiki tries to understand and reshape the material conceptually rather than just making it searchable.

Summarization

The system creates summaries, but useful summaries are not just shorter versions of text – they should preserve the structure of the argument. A weak summary says “this document discusses local LLM hosting tools.” A useful summary says “this document compares local LLM hosting tools by deployment complexity, GPU usage, API compatibility, and production readiness, positioning Ollama as easy for local use, vLLM as stronger for server workloads, and llama.cpp as flexible for quantized models.”

For technical knowledge, a summary should capture:

  • what problem it solves
  • what assumptions it makes
  • what tradeoffs it contains
  • what dependencies it has
  • what is still uncertain

This is where LLMs are genuinely useful, because they are good at compressing messy prose into structured explanations.

Structuring

Summaries alone are not enough – the system must also decide where knowledge belongs, which is the representation layer. Common structures include:

  • topic pages
  • concept pages
  • index pages
  • comparison pages
  • glossary entries
  • how-to pages
  • architecture notes
  • decision records
  • maps of related pages

A pile of summaries is not a wiki; a wiki needs page boundaries, links, and recurring structure, and a good LLM Wiki is not measured by page count but by whether pages become genuinely reusable.

Linking

Links define the shape of the knowledge system. In a normal document archive, relationships are often implicit; in an LLM Wiki, they should become explicit. Useful link types include:

  • concept to concept
  • article to summary
  • tool to comparison
  • problem to solution
  • architecture to implementation
  • source to derived page
  • glossary term to detailed page

This is one of the most important differences between LLM Wiki and basic summarization: summaries reduce text, but links build a knowledge graph.

Review and correction

This stage is optional only in toy systems; in serious systems, human review is essential. The review process should check:

  • whether summaries are faithful
  • whether links are useful
  • whether claims are sourced
  • whether pages are duplicated
  • whether concepts are misplaced
  • whether outdated information is marked
  • whether generated pages overstate certainty

LLM Wiki can reduce human effort, but it should never remove human responsibility.

LLM Wiki vs RAG

The cleanest distinction between LLM Wiki and RAG is timing.

Query-time synthesis

In RAG, the system retrieves information when a user asks a question.

query
  -> retrieve chunks
  -> assemble context
  -> generate answer

This is flexible and works well when:

  • the corpus is large
  • information changes often
  • questions are unpredictable
  • you need broad coverage
  • you cannot curate everything

But it may be less coherent for conceptual questions, because the model has to synthesize from fragments each time, which can produce inconsistent answers across similar queries.

Ingest-time synthesis

In LLM Wiki, the system performs synthesis before the question arrives.

sources
  -> summarize
  -> structure
  -> link
  -> query or browse later

This is less flexible but more coherent, and it works well when:

  • the corpus is manageable
  • the domain is stable
  • concepts repeat
  • human readability matters
  • you want reusable synthesis
  • you want a maintained knowledge layer

The main differences

Dimension RAG LLM Wiki
Main timing Query time Ingest time
Main operation Retrieve chunks Compile knowledge
Best corpus Large and changing Curated and stable
Output Generated answer Structured knowledge pages
Infrastructure Search index or vector DB Markdown or wiki structure
Strength Flexible access Reusable synthesis
Weakness Fragmented context Maintenance drift
Human readability Often indirect Usually direct

Complementary, not mutually exclusive

The debate should not be framed as “LLM Wiki or RAG” – that is the wrong question. LLM Wiki does not replace RAG in most production systems; both have distinct and complementary roles. A well-designed system may look like this:

raw documents
  -> source store
  -> LLM Wiki synthesis
  -> reviewed knowledge pages
  -> search index
  -> RAG over source and synthesis
  -> answer with citations

In that architecture, LLM Wiki improves the representation layer and RAG improves the access layer. Use RAG for retrieval over large and changing corpora, use LLM Wiki for compiled synthesis over stable and curated knowledge, and use both together when you need scale and coherence at the same time.

LLM Wiki vs adjacent systems

LLM Wiki vs summarization

A weak LLM Wiki is just a folder of generated summaries, and that is not enough. Summarization compresses content; LLM Wiki structures it. A real LLM Wiki needs stable pages, links, concepts, indexes, source tracking, revision history, maintenance workflows, and conflict detection – the wiki part matters as much as the LLM part.

LLM Wiki vs knowledge graph

A knowledge graph represents entities and relationships explicitly, while an LLM Wiki creates a softer, document-oriented graph through Markdown pages and links. A mature system can use both: the wiki provides human-readable explanations and the knowledge graph provides precisely structured, machine-queryable relationships.

LLM Wiki vs agent memory

LLM Wiki is also different from AI memory. Memory stores context that affects future behavior, while an LLM Wiki stores structured knowledge that can be read, searched, reviewed, and linked by both humans and systems.

Memory might remember:

  • the user prefers Go examples
  • the project avoids ORMs
  • the agent tried a command yesterday
  • a bug investigation failed

An LLM Wiki might store:

  • what Go database access patterns exist
  • how sqlc compares with GORM
  • why outbox patterns matter
  • how RAG differs from memory systems

Memory is behavioral context; LLM Wiki is represented knowledge – and mixing the two leads to systems that are hard to inspect, audit, or maintain.

When LLM Wiki works well

LLM Wiki works best for stable domains, personal research, curated corpora, technical documentation, and situations where repeated synthesis over the same material is wasteful.

Stable domains

LLM Wiki works best when the domain does not change every hour. Good examples include:

  • technical concepts
  • research notes
  • learning material
  • architecture patterns
  • book notes
  • model comparison notes
  • internal engineering principles
  • curated documentation
  • personal knowledge bases

If knowledge is stable enough to summarize without becoming stale within days, LLM Wiki can deliver lasting value that compounds as the wiki grows.

Research synthesis

Research synthesis is one of the strongest use cases, because researchers often read many sources and repeatedly ask the same meta-questions:

  • What are the main ideas?
  • Which sources agree?
  • Which sources conflict?
  • What concepts repeat?
  • What is the current state of the topic?
  • What should I read next?

LLM Wiki helps turn that research material into reusable structure – topic pages, comparison pages, contradiction notes, and related links – so the researcher does not have to rebuild the same mental map every time they return to a domain. It is especially useful when working with papers, technical articles, transcripts, documentation, notes, and experiment logs.

Personal knowledge systems

LLM Wiki fits naturally with PKM and the broader knowledge systems spectrum and second brain workflows because a personal knowledge system already contains:

  • notes
  • links
  • unfinished ideas
  • summaries
  • references
  • topic maps

An LLM can help maintain the structure by:

  • summarizing long notes
  • proposing links
  • creating topic pages
  • detecting duplicate concepts
  • extracting glossary terms
  • generating index pages
  • identifying gaps

The human remains the editor, which is the right relationship between human judgment and machine assistance.

Technical blogging

A technical blog can use LLM Wiki ideas internally even without building a full automated system. A well-structured site can include:

  • pillar pages
  • cluster index pages
  • topic summaries
  • related article maps
  • glossary pages
  • comparison pages
  • canonical explainers

This is not only SEO but knowledge representation: a well-structured technical blog becomes more valuable when articles are connected into a durable knowledge structure that both humans and AI systems can navigate.

Small team knowledge bases

LLM Wiki can work well for small teams with curated knowledge, including engineering decisions, product architecture, onboarding notes, support playbooks, internal standards, postmortems, and runbooks. The key condition is governance: someone must review and maintain the generated structure, because without clear ownership the wiki decays into noise regardless of how well it was initially generated.

When LLM Wiki is a poor fit

Highly dynamic data

LLM Wiki is weaker when information changes constantly. Live inventory, pricing feeds, incident status, financial market data, rapidly changing support tickets, and real-time logs are all better served by retrieval or direct API access. Compiling fast-moving data into static summaries is counterproductive unless you have a strong refresh process that keeps the compiled layer in sync with reality.

Large unmanaged corpora

LLM Wiki does not automatically scale to millions of documents. At large scale, the difficult problems extend well beyond generation and include:

  • access control
  • data lineage
  • ownership
  • deduplication
  • indexing
  • freshness tracking
  • evaluation
  • governance

A simple Markdown wiki is not equipped to address those needs, and at enterprise scale, LLM Wiki may become one layer inside a larger knowledge architecture rather than the whole system.

Low-quality sources

LLM Wiki cannot reliably fix bad sources. If the source material is contradictory, outdated, low quality, duplicated, incomplete, or badly scoped, generated pages may look polished but be wrong. This is dangerous precisely because a clean generated page creates false confidence – the formatting signals quality even when the underlying content does not justify it.

No review process

LLM Wiki without review is risky because generated structure creates authority. A bad answer in RAG may affect one query, but a bad generated wiki page may affect many future queries, readers, and agents that retrieve from it. The model may overgeneralize, miss exceptions, invent structure, merge incompatible ideas, hide uncertainty, create misleading links, or summarize outdated material as though it were current – so for any knowledge that actually matters, human review is not optional.

Limitations and failure modes

The main risks of building an LLM Wiki are stale summaries, hallucinated synthesis baked into the knowledge base, weak source tracking, maintenance cost, and false confidence in generated structure.

Maintenance drift

Knowledge drift happens when generated pages stop matching the underlying sources. This can happen because:

  • sources changed
  • new sources were added
  • old pages were not refreshed
  • summaries were edited manually
  • links became outdated
  • model output changed over time

Drift is the central operational risk of LLM Wiki, and a good system needs explicit refresh and validation workflows to catch it before it propagates.

Hallucinated synthesis

RAG can hallucinate at answer time, but LLM Wiki can hallucinate at ingest time, which is more subtle and more dangerous. If a generated wiki page contains a wrong synthesis, future users may treat that page as ground truth, and future AI systems may retrieve it and amplify the mistake further. Generated structure needs provenance, and every important claim should link back to its original sources so the hallucination can be caught during review rather than silently embedded in the knowledge base.

Over-structuring

Once you have an LLM that can create pages cheaply, it is tempting to create too many of them. You can end up with:

  • empty taxonomy
  • duplicate concepts
  • shallow pages
  • meaningless links
  • generated clutter
  • fake completeness

A useful wiki is not measured by page count but by whether pages are actually reused, linked, and updated over time.

Unclear ownership

The model cannot own the page. A serious system needs clear ownership rules covering:

  • who reviews pages
  • who approves updates
  • who deletes stale pages
  • who resolves contradictions
  • who decides canonical structure

Without that clarity, LLM Wiki becomes another abandoned knowledge base – well-intentioned, well-generated, and quietly ignored.

Architecture patterns

Pattern 1. Personal LLM Wiki

The personal pattern is the simplest and most practical version, best suited for individuals.

notes and sources
  -> LLM assisted summaries
  -> Markdown pages
  -> manual review
  -> [Obsidian](https://www.glukhov.org/knowledge-management/tools/obsidian-for-personal-knowledge-management/ "Using Obsidian for Personal Knowledge Management") or static site

It works well for researchers, writers, engineers, technical bloggers, students, and consultants, where the value comes from reducing repeated synthesis and making personal knowledge easier to navigate without requiring any team coordination or governance infrastructure.

Pattern 2. Team LLM Wiki

The team pattern is best for small groups and needs more governance than the personal version.

team docs
  -> ingest workflow
  -> generated draft pages
  -> review queue
  -> published wiki
  -> search or RAG layer

The review queue is critical here, because generated knowledge should never be published directly into a team source of truth without a human checkpoint – even a lightweight review process catches the most dangerous hallucinations before they become institutional knowledge.

Pattern 3. LLM Wiki plus RAG

This is often the most balanced architecture, giving you both raw source access and compiled synthesis.

raw sources
  -> LLM Wiki pages
  -> reviewed knowledge base
  -> search index
  -> RAG over raw and compiled knowledge
  -> cited answer

The RAG system can retrieve from original documents, generated summaries, topic pages, comparison pages, and glossary entries, which makes retrieval quality significantly stronger than operating over raw documents alone.

Pattern 4. LLM Wiki as site architecture

For a technical website, LLM Wiki ideas can guide content structure even without automation.

articles
  -> pillar pages
  -> topic maps
  -> comparisons
  -> internal links
  -> search and AI access

This turns a blog into a knowledge system where articles are not just posts but nodes in a structured map – a significant difference for both reader experience and machine-readable discoverability.

LLM Wiki design principles

Keep raw sources separate

Never lose the original source. Generated pages should not replace source documents but sit above them – the source layer provides evidence, the wiki layer provides interpretation, and losing the original means losing the ability to verify, challenge, or update the interpretation derived from it.

Use Markdown where possible

Markdown is boring and excellent. It is portable, readable, diffable, versionable, easy to edit, friendly to static sites, and friendly to PKM tools. Boring formats survive longer than clever platforms, which means a Markdown-based LLM Wiki built today will still be usable long after whatever proprietary database you might have chosen has gone through multiple breaking migrations. For syntax reference, see the Markdown Cheatsheet and the guide to Markdown Code Blocks, which are especially relevant when structuring wiki pages that include technical content.

Track provenance

Every generated page should answer:

  • What sources created this?
  • When was it generated?
  • When was it reviewed?
  • What changed?
  • Who approved it?

Without provenance, trust collapses over time as pages drift further from their origins. A practical page schema might look like this:

title
summary
status
sources
last_reviewed
related_pages
concepts
open_questions

For technical content, add:

applies_to
version
examples
tradeoffs
failure_modes

For research content, add:

claims
evidence
contradictions
confidence

Prefer fewer better pages

Do not generate a page for every minor idea. Prefer strong concept pages, useful comparison pages, topic indexes, canonical summaries, and glossary entries that earn their place. A small useful wiki with twenty well-maintained pages beats a large generated mess with two hundred pages nobody reads or updates.

Make links meaningful

Links should explain relationships rather than just connect pages at random. Useful link types include:

  • related concept
  • depends on
  • contrasts with
  • example of
  • source for
  • expands on
  • implementation of

Random links create noise and erode reader trust in the structure.

Mark uncertainty

LLM Wiki pages should not pretend all knowledge is equally certain. Useful status markers include:

  • confirmed
  • likely
  • disputed
  • outdated
  • needs review
  • source conflict
  • generated summary

These markers protect readers from false confidence and give maintainers a clear signal about which pages need attention.

How to evaluate an LLM Wiki

Do not only ask whether the generated pages look impressive – ask whether they improve knowledge work. Useful evaluation questions include:

  • Can users find concepts faster?
  • Are repeated questions answered better?
  • Are source links preserved?
  • Are contradictions easier to see?
  • Are pages reused?
  • Are summaries accurate?
  • Is stale content detected?
  • Does the wiki reduce repeated synthesis?
  • Does it help humans write or decide?
  • Does it improve RAG answer quality?

If the answer is no to most of these, the wiki is decoration regardless of how many pages it contains.

LLM Wiki and knowledge management

LLM Wiki belongs in knowledge management because it is fundamentally about representation, not primarily about model hosting, vector search, or agent execution. It answers a different question: how should knowledge be structured so that humans and AI systems can reuse it? That places it in the knowledge systems architecture layer, connecting naturally to PKM, wikis, RAG, agent memory, knowledge graphs, technical publishing, and research synthesis.

A clean layer model looks like this:

  • Human thinking – PKM, explore and develop ideas
  • Shared knowledge – Wiki, maintain canonical pages
  • Compiled knowledge – LLM Wiki, generate structured synthesis
  • Machine access – RAG, retrieve context at query time
  • Agent continuity – Memory, persist behavior and preferences

LLM Wiki occupies the compiled knowledge layer, and that position is what makes it useful – it is the layer that turns a pile of documents into something both humans and machines can navigate and reason over.

My opinionated take

LLM Wiki is important, but the hype is slightly wrong – it is not a RAG killer, but a reminder that knowledge representation matters. The industry spent years optimizing retrieval pipelines, and that work was necessary, but many systems still retrieve from badly structured knowledge. Better embeddings and better rerankers help, but they cannot fully compensate for a weak knowledge layer.

LLM Wiki pushes the conversation back toward structure by asking better questions:

  • What are the core concepts?
  • What is canonical?
  • How do ideas connect?
  • What should be summarized once?
  • What should be retrieved fresh?
  • What should be reviewed by humans?

That is the right conversation, and the future is not just better vector search but layered knowledge systems where representation, retrieval, and memory each play a distinct and well-understood role.

Conclusion

LLM Wiki is an architecture pattern for compiled knowledge that uses language models to help transform source material into structured, linked, reusable knowledge before questions are asked. Its core workflow is:

summarize
  -> structure
  -> link
  -> review
  -> reuse

Compared with RAG, the main difference is timing: RAG performs synthesis at query time, while LLM Wiki performs synthesis at ingest time, which makes it valuable for stable domains, research synthesis, personal knowledge bases, technical blogs, and curated team knowledge.

But it has real limitations. It can drift when sources change, hallucinate when model output is wrong, create false confidence when review is absent, and collapse into noise when ownership is unclear. Used badly, it becomes another abandoned wiki. Used well, it becomes the representation layer between raw documents and AI systems – not a replacement for RAG, but the missing layer that makes retrieval worth using.

Sources and further reading