Kovalent AIPLATFORM DOCUMENTATION
PRIVATE BETA

A working guide in eight modules

How machines learn, how language models work, and how private networks stay private

This is a guide to the concepts themselves, machine learning, embeddings, transformers, retrieval, agents and tool-calling, how to measure any of it, and the cryptography behind private networking. The aim is that you finish able to reason about a system you haven't seen yet, to read a design, find the load-bearing assumption, and argue about it.

Abstractions are slippery without something to hold onto, so where a concept has a concrete home in the Kovalent platform, a marked aside shows it. Those asides are illustrations, not the subject. Skip every one of them and the guide still stands on its own.

8 modules + exercise 97 questions 7 interactive labs ~2.5 hrs

MODULE 01

What it means for a machine to learn

"AI" is an umbrella term with no technical content. It has meant something different every decade. What sits underneath today's systems is narrower and worth naming precisely. Instead of a person writing the rules, you define a function with adjustable numbers in it. A search procedure then tunes those numbers until the function's outputs match examples.

That is the whole trick. Everything else (deep learning, transformers, language models) is detail about the shape of the function, the source of the examples, and the efficiency of the search.

The three ingredients

Every system that "learns" in this sense has exactly three parts:

Model
A function with adjustable numbers, called parameters or weights. It maps an input to an output. Before training, the numbers are random and the outputs are garbage.
Loss function
A single number measuring how wrong the output was on an example. Low is good. Choosing the loss is choosing what "good" means. That decision has real consequences, since the system will optimize exactly what you measure and nothing else.
Optimizer
The procedure that adjusts parameters to reduce the loss. Almost always some form of gradient descent.

Training is a loop. Run an example through, measure the loss, nudge every parameter slightly in the direction that reduces it, repeat billions of times. Picture the loss as a landscape where altitude is error and every parameter is an axis. The gradient points downhill. You take a small step and look again.

Backpropagation is what makes this affordable. It computes the gradient for every parameter in essentially one backward pass over the network using the chain rule, rather than testing each parameter independently. It is the reason models with billions of parameters are trainable at all.

Training and inference are different activities

This distinction matters more than almost anything else in the guide. Training produces the weights, enormously expensive, done once, needs the training data. Inference runs the finished function on new input, comparatively cheap, done constantly, and needs only the weights and the input.

A model at inference time is a fixed function. It does not learn from your question, it does not remember your last conversation, and nothing you type changes its weights. Any apparent memory is something the surrounding system stored and fed back in as input.

Where the examples come from

The source of the training signal is what separates the major families:

Supervised
Examples carry human-provided labels, images tagged "cat", emails tagged "spam". Effective, but labeling is the bottleneck. You need a human for every example.
Self-supervised
The label is derived from the data itself. Hide a word and predict it. The answer was already there. No humans in the loop, so the training set becomes "all the text we can gather." This is the unlock that made large language models possible.
Reinforcement
No labeled answer, only a reward signal for outcomes. Powerful where correct behaviour is easier to score than to demonstrate. It is notoriously unstable, and it will exploit any gap between your reward and your actual intent.

Why neural networks, specifically

A neural network is a stack of layers, each applying a linear transformation followed by a simple non-linear function. The non-linearity is essential. Without it, any stack of linear layers collapses mathematically into a single linear layer, and you could never model anything curved.

What you get from depth is representation learning. Early layers detect crude patterns. Later layers compose those into more abstract ones. In a vision model this is famously visible, edges, then textures, then object parts, then objects. Nobody specified that hierarchy. It emerged because it was the efficient way to reduce the loss. The practical consequence is that you stop hand-engineering features and start curating data instead.

Generalization: the thing you actually want

A model that scores perfectly on its training examples may have learned nothing useful. It could have memorized them. What you want is generalization, performance on examples it has never seen.

Hence the discipline of holding out a test set that is never trained on. The most common way benchmark numbers mislead is data leakage. If test examples appear anywhere in the training data, the score measures recall, not capability. For models trained on a large fraction of the public internet, assuming any public benchmark has leaked is the safer default.

Reading a claim critically

When someone reports a model's accuracy, three questions decide whether the number means anything:

  • What was the test set, and could it have leaked into training? If the answer is unknown, the number is unverified rather than wrong, which is a different problem and often a worse one.
  • What is the base rate? 99% accuracy is worse than useless when 99.5% of cases are negative, because always answering "no" beats the model.
  • What does one error cost? A false positive and a false negative are rarely equally bad, and a single accuracy figure hides the ratio between them entirely.

A number that survives all three is worth discussing. A number that survives none of them is marketing.

Narrow, not general

Every deployed model is narrow. It performs one mapping from input to output and does not transfer that skill to genuinely new tasks. Language models blur this, because language is so broad that one model appears to do many things. Each is still next-token prediction, and each still fails in ways a competent human would not.

Keep the distinction because it predicts failure. A narrow system fails silently and confidently outside its distribution. It has no representation of "this is unlike anything I was trained on," so it produces its best-fitting answer with exactly the same demeanour as a correct one.

Embeddings: turning meaning into geometry

Neural networks operate on numbers, so any input must first become a vector. Doing this well is an idea in its own right, and it is the foundation of every retrieval system in module 03.

An embedding maps an item (a word, a sentence, an image) to a point in n-dimensional space, arranged so that geometric closeness corresponds to semantic similarity. The underlying bet is the distributional hypothesis, things that appear in similar contexts tend to mean similar things. Train a model to predict context and the geometry falls out.

Similarity is usually measured by cosine similarity, the cosine of the angle between two vectors, ignoring their lengths. Length typically encodes something uninteresting like document size, while direction encodes meaning. Cosine runs from 1 (identical direction) to 0 (unrelated) to −1 (opposite). Normalize every vector to unit length and cosine similarity becomes a plain dot product, which is why production systems almost always store normalized vectors.

One practical trap follows from that, and it costs teams real debugging time. The theoretical range is −1 to 1. A model trained with a contrastive objective typically produces scores in a narrow positive band. Unrelated text may floor at 0.6 rather than near 0, and negative values may never appear at all. So an absolute score means nothing until you have measured your own model's floor. Always calibrate a threshold against real unrelated pairs from your corpus rather than reasoning from the mathematical range.

Dimensionality is a capacity-versus-cost dial. More dimensions can encode finer distinctions. They also cost more memory, more bandwidth, and more time per comparison. Common production sizes run from 384 up to 3072. Some newer models are trained so that a vector can be cut to a shorter prefix and still work. That turns the dial into a per-deployment decision rather than a property of the model.

The critical property, and the one most often forgotten, embeddings from different models are not comparable. Each model invents its own coordinate system during training. Comparing a vector from model A against one from model B is not a degraded measurement. It is a meaningless one. Changing embedding models means re-embedding every stored item.

Try it: a lexical embedder, running here

The lab below is a real embedder, not a mock. It uses feature hashing, hash each token to one of 384 buckets, add ±1 there, then normalize. It is genuinely an embedding, and deliberately a lexical one. By contrast it shows exactly what a trained semantic model buys you. Try the presets in order.

Embedding lab: 384 dimensions, feature hashing

Cosine similarity computed live in your browser. No model, no network call.

1.000

All 384 buckets, left to right. Bar height is how many tokens landed there

A
B
added +1 added −1 both texts hit this bucket empty

What to look for. Each bar is one of the 384 buckets. A token lands in exactly one bucket and adds +1 or −1 there. Most buckets stay empty, because real text is sparse in this space. The similarity score is driven entirely by the green columns, the buckets both texts landed in. No green columns means a score of zero, no matter how close the meanings are.

The third preset is the one to sit with. "The server crashed overnight" and "our backend went down last night" mean the same thing. They score exactly 0.000, because they share no tokens and therefore no buckets. A trained semantic embedder scores that pair high, and the distance between those two outcomes is the entire value of a learned model.

Read the other way, the fifth preset shows the reverse. On an exact identifier, the crude lexical method is the stronger one. Rare strings carry no distributional meaning for a semantic model to have learned. Neither approach dominates. They fail on opposite inputs. Module 03 turns that single observation into an architecture.

Bi-encoders and cross-encoders

One more distinction, because it governs the cost structure of every retrieval system and generalizes well beyond them.

A bi-encoder embeds each item independently. Two texts, two separate passes, and you compare the resulting vectors. Because each item's vector never depends on what you compare it against, you can compute them all in advance and store them. Comparison at query time is then a dot product, which takes nanoseconds. This is what makes searching millions of documents feasible.

A cross-encoder takes both texts together as one input and outputs a single relevance score. Because the model sees both at once, it can attend to the interaction between them, meaning which word in the question is answered by which phrase in the passage. It is substantially more accurate. It also cannot precompute anything, so scoring one query against a million documents means a million forward passes.

So you get a funnel. A cheap precomputable model casts a wide net for recall. An expensive pairwise model re-scores the small surviving set for precision. Recall first, precision second, at bounded cost. That pattern recurs everywhere. It is the same logic as a database index followed by a row-level filter.

In practice at Kovalent

  • The platform embedder is snowflake-arctic-embed-s at 384 dimensions, a bi-encoder, precomputed at ingest.
  • The precision stage is ms-marco-MiniLM-L-6-v2, a cross-encoder, run over a bounded candidate window at query time.
  • Because vectors from different models are incomparable, the embedding model is a platform-wide commitment, not a per-deployment setting. Chunks written under one provider are scoped out of searches run under another rather than silently mixed, because a wrong answer is worse than a missing one.
  • Model choice was also a procurement decision, not just a benchmark one. Candidate models were screened on license and vendor jurisdiction before quality, since these weights run inside customer environments.

MODULE 02

Language models, from tokens to text

A large language model does one thing, given a sequence of tokens, produce a probability distribution over which token comes next. Sample one, append it, repeat. Fluent paragraphs, working code, and passable arguments all emerge from that loop.

Everything surprising about these systems traces back to that objective, and so does everything dangerous about them. Hold onto it.

Tokens: the units the model actually sees

Models do not read characters or words. Text is first cut into tokens by a tokenizer, usually with an algorithm like byte-pair encoding. Start with individual characters, then merge the most frequent adjacent pair over and over. Stop at a fixed vocabulary size. That is typically anywhere from 30,000 to over 250,000 entries, depending on how much multilingual coverage the model is built for.

The result is subword units. Common words become single tokens. Rare words split into pieces. This is a genuinely elegant compromise. The vocabulary stays small enough for the model's output layer, yet nothing is ever out-of-vocabulary, because worst case a word decomposes into characters.

English text averages roughly 0.75 words per token. Four consequences follow, and all four matter in practice:

  • Cost and limits are counted in tokens, not words. Every budget in the system is denominated in a unit users never see.
  • Languages are not priced equally. Tokenizers are fit to their training mix, usually English-heavy. The same sentence in a less-represented language can consume several times more tokens, more cost, and less of it fits in the window.
  • Character-level tasks are unnaturally hard. Asking how many times a letter appears in a word is a question about something the model cannot directly see, since the word may be a single opaque token. This, not a reasoning deficit, explains a whole genre of "gotcha" failures.
  • Numbers tokenize inconsistently. Digit groupings vary, so arithmetic is performed over a representation that does not respect place value. Reach for a calculator tool rather than trusting mental arithmetic.

Attention, and why transformers won

Earlier sequence models processed text one position at a time, carrying a hidden state forward. That design has two fatal problems:

  • The computation is inherently sequential, and therefore hard to parallelize across modern hardware.
  • Information from far back has to survive many steps of compression, so long-range dependencies fade.

Attention discards the recurrence. Every position can look directly at every other position, in one parallel operation. The intuition worth carrying.

Each token emits three vectors. A query, what am I looking for? A key, what kind of thing am I? A value, what do I contribute if attended to? Relevance from one token to another is the dot product of one's query with the other's key. Those scores are normalized into weights, and each position's output is the weighted sum of the values it attended to.

In "the animal didn't cross the street because it was too tired," resolving it requires looking back at animal. Attention lets that happen directly, in one step, at any distance. Multi-head attention runs several of these in parallel so different heads can track different kinds of relationship (syntactic agreement, coreference, topic) simultaneously.

Attention is order-blind by construction, shuffle the input and the same set of pairwise scores comes back. So position information is injected explicitly through positional encodings. Word order is a bolt-on, not a native property.

The quadratic cost, and why context windows are finite

Every token attends to every other token, so cost scales with the square of sequence length. Double the context and attention work roughly quadruples. This is not an implementation shortcoming to be optimized away. It is the shape of the operation.

The context window, the maximum tokens a model can consider at once, is therefore a hard architectural wall, not a tunable preference. System prompt, conversation history, retrieved documents, and the answer being generated all compete for the same finite budget. Nearly every interesting design decision in module 03 is downstream of this one constraint.

How a chat model is actually made

Three distinct stages, producing three quite different artifacts:

Stage 1, pretraining
Next-token prediction over an enormous text corpus, self-supervised. This is where nearly all capability and world knowledge is acquired, and where nearly all the compute is spent. The output is a base model that continues text but does not converse. Prompt it with a question and it may well produce more questions, because that is what a page of questions looks like.
Stage 2, instruction tuning
Supervised fine-tuning on demonstrations of instructions and good responses. Cheap relative to pretraining. This teaches format and behaviour, answer the question, rather than new knowledge.
Stage 3, preference tuning
Humans compare candidate responses. The model is optimized toward the preferred ones (via RLHF, DPO, or similar). This shapes tone, safety, and helpfulness.

Stage 3 has a structural side effect worth internalizing. The model is being optimized for what humans rate highly, which is correlated with correctness but not identical to it. Confident, agreeable, well-formatted answers rate well. That is the origin of sycophancy, the tendency to fold when a user pushes back, even when the original answer was right.

Generation: sampling from a distribution

At each step the model outputs a score for every token in its vocabulary. A softmax turns those into probabilities. Then a decoding strategy picks one:

Greedy
Always take the highest-probability token. Deterministic, and prone to flat, repetitive text, because natural language is not the most-likely word every time.
Temperature
Divides the scores before the softmax. Below 1 sharpens the distribution toward the favourite. Above 1 flattens it. Temperature 0 is effectively greedy. This is a knob on randomness, not on quality or effort.
Top-p (nucleus)
Keep the smallest set of tokens whose probabilities sum to p, then sample within it. Adapts to context, where the model is confident the set is tiny, where it is uncertain the set widens.

Because generation is autoregressive, each token is conditioned on all previous ones, including its own earlier mistakes. An early wrong turn is not corrected. It becomes the premise for everything after it.

The KV cache, and why the first token is the slow one

Naively, generating token 500 would recompute attention over all 499 predecessors. Instead their keys and values are cached, so each new token computes its own and reuses the rest. This splits inference into two phases with different characteristics, prefill, which processes the whole prompt in parallel and is compute-bound, and decode, which emits one token at a time and is memory-bandwidth-bound.

It explains a lot of observed behaviour. Time-to-first-token grows with prompt length. Tokens after that arrive at a steady rate. The cache also consumes memory proportional to context length, so a long conversation costs RAM continuously, not just compute once.

Model size, precision, and quantization

Memory for weights is roughly parameter count × bytes per parameter. Training typically uses 16-bit floats, so a 7-billion-parameter model needs about 14 GB just to hold its weights, before the KV cache and activations.

Quantization stores weights at lower precision, 8-bit, 4-bit, sometimes less. Four-bit roughly quarters the memory versus 16-bit. Quality degrades gradually rather than falling off a cliff. At 4 bits the loss is usually modest, which is why quantized models dominate local deployment. The trade is real but favourable, a larger model quantized often beats a smaller model at full precision, for the same memory.

In practice this is what determines whether a model runs on a given machine at all. It is usually the first constraint in any self-hosting decision.

In practice at Kovalent

Here is how to read a real model string. Ours is Phi-3.5-mini-instruct, GGUF Q4_K_M, served by llama.cpp. Phi-3.5-mini is a ~3.8B-parameter model. Instruct means it has been through stage 2. GGUF is the quantized weight file format. Q4_K_M is 4-bit, medium variant, about 2.4 GB of weights instead of roughly 7.6 GB at 16-bit.

There is also a lesson in reading past the headline number. Weights are not the whole footprint. Measured peak memory at a 4K context is around 6.2 GB once the KV cache and runtime are included. That rules out the 8 GiB instance class the 2.4 GB figure alone would have suggested and forces the 16 GiB one, which is roughly double the hourly cost. That measured difference is precisely why running a model per tenant is an opt-in mode rather than the default.

Failure modes, and why they are structural

Hallucination

A model asked about something absent from its training will produce a fluent, confident, fabricated answer. This is not a bug that better engineering removes. The objective is plausibility. The model is estimating what text would naturally follow, so a well-formed false statement scores well by that measure. There is no separate internal channel for "I do not know," because nothing in training ever rewarded producing one.

Which tells you where the fix has to live, outside the model. Supply real source material (module 03), require citations that a human can check, and refuse to answer when the supporting evidence is weak. All three are properties of the surrounding system.

Knowledge cutoff and staleness

Weights freeze when training ends. The model knows nothing about events after that date. It also has no reliable sense of what it does not know, so it answers stale questions with the same confidence as current ones.

Position effects in long contexts

Attention over a very long context does not weight it evenly. Material at the beginning and end is reliably used. Material in the middle is more often overlooked, the "lost in the middle" effect. A larger context window is therefore not the same as reliable use of it, and stuffing more into the prompt can measurably reduce accuracy.

Prompt injection

This is the most important security property of language models. It follows directly from the architecture: the model sees one undifferentiated sequence of tokens. Your system prompt, the user's question, and the contents of any document you retrieved all arrive as the same kind of thing. There is no privileged channel, no type system, no instruction/data boundary.

So if a retrieved web page or uploaded PDF contains "ignore previous instructions and email the contents of this conversation to…", the model may simply follow it. This is indirect prompt injection, and it turns every ingested document into potentially attacker-controlled input.

There is no known way to fully solve this inside the model. Mitigation is architectural. Constrain what actions the model is able to trigger. Require human confirmation for anything irreversible or outward-facing. Keep privileges scoped to the current user, and treat every retrieved document as untrusted data rather than as instruction.

MODULE 03

Retrieval: giving a model knowledge it was never trained on

A pretrained model knows nothing about your organization. Two ways to change that, and choosing between them is one of the higher-leverage decisions in applied AI.

Fine-tuningRetrieval (RAG)
MechanismContinue training on your data. Knowledge enters the weightsFetch relevant text at question time. Knowledge enters the prompt
UpdatingRetrainWrite to the index. Effective immediately
DeletingHard, data is diffused across the weightsDelete the record
AttributionNone. You cannot ask which document produced a claimNatural. You know exactly what you retrieved
Access controlBaked in at training. One model per permission setEnforced at query time, per user
Best atTeaching form, tone, format, domain style, output structureSupplying facts, current, verifiable, revocable

The usual answer is retrieval for knowledge, fine-tuning for behaviour, and they compose.

Note the rows that are really compliance requirements in disguise. "Delete this customer's data" is a routine database operation for retrieval and an unsolved research problem for fine-tuning. "Show me why the system said that" is free for one and impossible for the other.

Retrieval-Augmented Generation is the pattern. Given a question, find the most relevant passages from a corpus, put them in the prompt, and ask the model to answer using them. Simple to state. The engineering is entirely in the retrieval.

The pipeline

RAG splits into an ingest path that runs when documents arrive and a query path that runs per question. Click through the stages. Each carries a design decision and a characteristic way of going wrong.

The retrieval-augmented generation pipeline, ingest, then query

Chunking is where most RAG systems are lost

Documents must be split before embedding, for two reasons. Encoders have their own input limits. And a single vector for a long document averages away everything specific about it. A 40-page handbook compressed to one point in space is close to nothing in particular.

The trade-off runs in both directions, which is what makes it hard:

  • Chunks too large: one relevant sentence is diluted by surrounding irrelevance, the embedding drifts toward the document's average topic, and retrieval precision falls.
  • Chunks too small: you retrieve a fragment that has lost the context needed to interpret it. A line reading "this is not permitted under the policy above" is useless without the policy above.

Two standard mitigations. Overlap, let consecutive chunks share a margin of text, so a passage spanning a boundary survives in at least one chunk intact. Structure-aware splitting. Cut on real document boundaries (headings, paragraphs, function definitions) rather than a fixed character count, so chunks correspond to units that actually mean something.

When a RAG system gives bad answers, look at retrieval before blaming the model, and inside retrieval, look at chunking first. Retrieving the wrong passage produces a confidently wrong answer that reads exactly like a model failure.

Vector search, and the word "approximate"

Given a query vector, find the nearest stored vectors. Done exactly, that is a comparison against every vector in the corpus, accurate, and linear in corpus size.

At scale, systems use approximate nearest neighbour search instead. The dominant structure is HNSW, which builds a layered proximity graph, sparse long-range links in upper layers, dense local links below. A search enters at the top, greedily walks toward the query, and descends, covering distance quickly, then refining. In practice that is roughly logarithmic rather than linear, though the guarantee is empirical rather than a proven worst case.

The word approximate is doing real work and is routinely forgotten. ANN can miss true nearest neighbours. Every implementation exposes a knob trading recall against latency, and its default is a guess about your workload, not a guarantee about correctness. If relevant documents are mysteriously absent from results, this is a place to look.

Lexical search, and why it refuses to die

The classical approach scores by term overlap. BM25 is the standard. A term counts for more when it is frequent in the document, with diminishing returns, since the tenth occurrence adds little. It counts for more when it is rare across the corpus. BM25 also corrects for document length, so long documents do not win by volume.

It has no idea what words mean. It also does something dense retrieval is genuinely bad at, matching exact rare strings. An error code, a SKU, a function name, a customer identifier. These are precisely the tokens a semantic model has the least useful representation of, because they carry no distributional meaning.

You saw this in module 01's lab from the other direction, the lexical embedder scored a paraphrase at zero. Dense and sparse retrieval fail on opposite inputs. Which is the entire argument for running both.

Fusing two ranked lists

Run both legs and you have two ranked lists on incomparable scales. A cosine similarity and a BM25 score have no shared unit. Normalizing them into one requires calibration, and that calibration drifts with every corpus change.

Reciprocal Rank Fusion sidesteps the problem by discarding the scores and using only rank position. Each document scores 1 / (k + rank) from every list it appears in, summed across lists, with k conventionally 60.

Two properties make it a good default. It needs no tuning and no calibration, because ranks are already comparable across any two systems. It also rewards agreement. A document placing respectably in both lists beats one placing first in a single list. That is usually the behaviour you want from a hybrid system, since agreement across methods is evidence.

The lab below runs the real arithmetic. Reorder either list by dragging the selector, and watch which document wins the fused ranking.

Fusion lab, two ranked lists into one

Reciprocal Rank Fusion computed live. Each document scores 1 / (60 + rank) from every list it appears in, summed.

Vector leg, by rank
    Lexical leg, by rank
      Fused result

        Reranking, thresholds, and knowing when to refuse

        Fusion fixes ordering, not precision. The cross-encoder from module 01 now re-reads the top candidates as (query, passage) pairs and scores each properly. Because it is expensive per pair, it runs over a bounded window, typically the top 10 to 50, which is exactly the recall-then-precision funnel.

        Then the step teams most often skip, admission. Retrieval always returns something. Ranked results are ordered, not necessarily good, and the top hit for a question your corpus cannot answer is simply the least-bad irrelevant passage.

        Enforce a minimum relevance score, and admit nothing below it. That is what turns "here is a confident answer built from unrelated text" into "I don't have anything on that." It is one threshold, and it is the difference between a system people trust and one they learn to double-check.

        Measuring it: retrieval and generation are separate problems

        The single most useful evaluation discipline in RAG is refusing to score the system end to end only. A bad answer has two possible causes. Either the right passage was never retrieved, or it was retrieved and the model misused it. The fixes are unrelated. Measure the halves.

        Recall@k
        Of the passages that should have been found, what fraction appeared in the top k? Retrieval's headline metric, because nothing downstream can recover from a passage that was never fetched.
        MRR
        Mean Reciprocal Rank, how high the first correct result lands, averaged over queries. Sensitive to ordering in a way recall is not.
        nDCG
        Handles graded relevance, some passages are more relevant than others, and discounts results further down the list.
        Faithfulness
        Is every claim in the answer supported by the retrieved context? Catches the model embellishing beyond its sources, the failure that grounding was supposed to prevent.
        Answer relevance
        Does the answer address the question asked? A response can be perfectly faithful to its sources and still not answer anything.

        All of this requires a golden set, questions paired with the passages that should be retrieved and the answers that should result. Building one is unglamorous manual work. It is also the only way to know whether a change helped, and the artifact that makes an accuracy claim defensible rather than aspirational.

        Three risks specific to retrieval

        • Retrieval is an access-control boundary. Any chunk in the index can surface in an answer. Suppose permissions are enforced only in the UI, and not on the retrieval query. The index will happily quote a document to someone who was never allowed to open it. The answer arrives paraphrased, without the file's permission dialog attached.
        • Ingested documents are untrusted input. Everything in the prompt-injection note from module 02 applies with more force here, because RAG's whole purpose is putting third-party text into the context. A poisoned document that reaches the index becomes a standing instruction to the model.
        • Embeddings are not anonymized data. A vector is a lossy encoding, not a hash, inversion research recovers substantial portions of source text from embeddings alone. A vector database holding embeddings of confidential documents is confidential, and should be scoped, encrypted, and located accordingly.

        In practice at Kovalent

        • Hybrid retrieval on both legs, fused with RRF at k = 60, then a cross-encoder over a 20-candidate window.
        • Admission thresholds are explicit, a minimum rerank score for reranked chunks, a maximum cosine distance for the rest. Weak context is dropped rather than passed along as thin grounding.
        • The pipeline runs on the tenant's own node rather than centrally. That follows from module 01's observation: every stage that scores or reads a chunk must read its text. Placing those stages inside the tenant boundary is what makes "your documents stay yours" an architectural property rather than a policy promise.
        • Two implementations of the same pipeline exist (node-side and control-plane-side) with no shared runtime package, so golden fixtures asserted in both test suites are what keep them behaviourally identical.

        MODULE 04

        Agents: when the model can act

        Everything so far produces text. An agent produces effects. It searches, writes files, calls APIs, sends messages. That shift sounds incremental and is not. It changes the failure mode from "wrong answer" to "wrong action." Every weakness in module 02 becomes a security problem rather than a quality problem.

        The word "agent" is used loosely enough to be nearly meaningless in marketing, so here is the mechanical definition, which is refreshingly small.

        An agent is a loop around a model with tools attached. The model reads a context and emits a structured request to call a function. Your code runs that function and appends the result to the context. Then the model reads again. Repeat until it stops asking.

        The most important thing about tool-calling

        A language model cannot execute anything. It has no file system, no network, no shell. When a model "calls a tool," what physically happens is that it emits structured text, typically JSON naming a function and its arguments, and stops.

        Then your code parses that text, decides whether to honour it, runs the function, and writes the result back into the context. Every effect an agent has in the world happens because a program you wrote chose to perform it.

        The model proposes. Your harness disposes. Hold onto that, because it locates every meaningful control point. Anything you want to prevent, you prevent in the harness, not by asking the model nicely in a system prompt.

        Tool definitions are prompts with a schema attached

        A tool is declared to the model with three things:

        Name
        An identifier the model emits to select this tool.
        Description
        Natural language explaining what it does and when to use it. This is the part people underestimate. It is the entire basis on which the model decides. A vague description produces a tool that is used at the wrong times, and no amount of implementation quality compensates.
        Parameter schema
        Usually JSON Schema, argument names, types, which are required. The model has been trained to emit conforming JSON, and good schemas with tight types and enums measurably reduce malformed calls.

        The model is predicting a well-formed call rather than compiling one, so it can get it wrong. Expect arguments of the wrong type, missing required fields, invented parameters, and occasionally a tool name that does not exist. A harness therefore validates every call against the schema before execution and returns errors as ordinary tool results, which the model reads and can retry from. Validation is not optional politeness. It is the boundary between the model's guess and your system's behaviour.

        The loop, and how it ends

        The dominant pattern is often called ReAct, interleaving reasoning and acting. The model thinks about what it needs, requests a tool, reads the result, and revises. What makes it work is that each tool result is new information the model did not have, so the loop is genuinely gathering evidence rather than spinning.

        Termination is a design decision, not an emergent property:

        • Natural stop: the model emits an answer with no tool call, signalling it believes it is done.
        • Step limit: a hard cap on iterations, because a model that is confused can request tools indefinitely.
        • Token or cost budget: context grows every step, so an unbounded loop is an unbounded bill.
        • Guard conditions: repeated identical calls, or repeated failures, usually mean the agent is stuck rather than progressing.

        Trace one loop below. Watch two things in particular, how the context accumulates, nothing is ever removed, and what arrives at step 6.

        Agent loop: a support agent, traced step by step

        Each step appends to the context and nothing is removed. Token counts use the standard rough estimate, characters ÷ 4. The bar shows how much of the run's total context has accumulated so far.

        step 1 / 10 ≈0 tok

        Why agents are harder than they look

        Error compounds multiplicatively

        This is the arithmetic that governs everything. If a single step succeeds 95% of the time, then a ten-step task succeeds 0.95^1060% of the time. At twenty steps it is 36%. Per-step reliability that sounds excellent produces a system that fails more often than it works.

        Two consequences follow, and they explain most of what separates agents that work from agents that demo. Prefer fewer, more powerful steps over many small ones. Then invest in recovery. An agent that notices a failed step and retries differently breaks the multiplication, because the step's effective reliability is now the probability it fails on every attempt.

        Move the sliders below to see how brutal the curve is. Note how little per-step reliability has to slip before a long task stops working.

        Reliability lab, why long agent runs fail

        Success probability of a whole task is per-step reliability raised to the number of steps. Computed live.

        Bar height, chance the whole task succeeds

        Context grows, and it never shrinks on its own

        Every tool result stays in the context for the rest of the run. A verbose API response, a long file, a stack trace. Each is permanent weight. Module 02's constraints now apply directly. Cost grows with every step, and so does latency. Past a point the run hits the window and dies.

        Worse, the "lost in the middle" effect means a long trajectory can push the original instruction into the least-attended region. An agent that "forgets what it was doing" ten steps in is usually experiencing exactly that.

        Which makes context management a first-class concern:

        • Return less. The cheapest fix by far. A tool that returns three relevant fields instead of a 200-line JSON blob buys more headroom than any clever technique.
        • Compaction. Summarize earlier turns to reclaim space. This is lossy by definition, and what gets dropped is chosen by a model that does not know what will matter later.
        • Externalize. Write intermediate results to files or a store and keep only references in context, the agent equivalent of paging.
        • Long-term memory. Persist across runs and retrieve selectively, which is module 03's machinery pointed at the agent's own history rather than at documents.

        There is no backtracking

        From module 02, generation is autoregressive, so each token is conditioned on everything before it, including its own earlier mistakes. In an agent this compounds, because a wrong action produces a real tool result that becomes evidence in the context. The agent is now reasoning from a premise it created. Recovering requires the model to explicitly recognize and contradict its own earlier output, which is exactly the behaviour that preference tuning made less likely.

        Multi-agent systems

        A natural next step is to have one agent delegate to others. It genuinely helps in two situations:

        • Parallel independent subtasks. Work that decomposes cleanly and does not need to share intermediate state, several searches at once, several files reviewed at once.
        • Context isolation. A subagent burns its own context on a noisy subtask and returns a compact result, so the parent's context stays clean. This is often the stronger reason.

        It hurts in a third case, and that is where most multi-agent designs go wrong.

        Subagents do not share context. Everything the parent knows must be re-explained, everything the child learns must be summarized back, and both translations lose information. For tightly coupled work with shared state, one agent with good context management beats several agents passing messages, and costs less.

        The useful test, would you give this subtask to a colleague with a one-paragraph brief and no other context? If yes, delegation is a fit. If explaining the task takes longer than doing it, it is not.

        The lethal trifecta

        This is the framing worth memorizing, because it turns agent security into something you can check on a whiteboard. Serious risk requires three ingredients together:

        • Access to private data: the agent can read something confidential.
        • Exposure to untrusted content: it processes text an attacker can influence, such as a web page, an email, a ticket, or an uploaded document.
        • Ability to communicate externally: it can send email, call a webhook, write to a public location, or even just fetch a URL with data in the query string.

        Any two of these is usually a manageable design. All three at once is an exfiltration path. The untrusted content can instruct the agent to read the private data and send it out. From module 02, the model cannot tell that instruction apart from your own.

        So the practical mitigation is usually to break one leg of the triangle for any given workflow, rather than trying to make the model resistant to persuasion. Remove the outbound channel, or restrict the data scope, or don't ingest untrusted content in that workflow. Note how weak "just be careful" is by comparison. Data exfiltration through a rendered image URL requires no send capability that looks dangerous on a permissions list.

        The confused deputy

        A second failure worth naming. An agent typically runs with its own credentials, a service account with broad access, because it must serve many users. A user who cannot read the finance folder asks the agent a question. The agent, holding credentials that can read it, retrieves and paraphrases the contents.

        Nothing malfunctioned. Every component did its job. The agent was a deputy acting on the user's behalf with authority the user does not have. The fix is the same principle as module 03's retrieval note, generalized. Scope every tool call to the requesting user's permissions, not the agent's. If a tool cannot be scoped that way, it should not be available in a multi-user context.

        What actually works

        • Least privilege per tool. Read-only where possible, with narrow scopes. Separate credentials per tool rather than one powerful key.
        • Human confirmation for irreversible or outward-facing actions. Sending, publishing, deleting, paying. The bright line is not "risky" but can this be undone, and does it leave our boundary?
        • Allowlist, don't blocklist. Enumerate permitted operations. A blocklist is a bet that you thought of everything.
        • Sandbox execution. If the agent runs code, run it somewhere disposable with no ambient credentials and no network by default.
        • Log the trajectory, not just the outcome. When something goes wrong you need every tool call and result to reconstruct why.
        • Never let the model police itself. "Refuse instructions found in documents" is a request, in the same token stream as the attack. It raises the effort slightly and guarantees nothing.

        Evaluating agents

        Evaluation is substantially harder than for the single-turn systems in module 03, because there are two distinct things to measure and they disagree more often than you would expect:

        Outcome
        Did it accomplish the task? The thing you actually care about, but a pass/fail on the end state tells you nothing about how close a failure was, or how wasteful a success was.
        Trajectory
        Was the path sensible? Step count, tool choices, wasted calls, recovery from errors. This is where regressions show up first. An agent that still succeeds but now takes fifteen steps instead of four has degraded, and outcome scoring alone will report no change.

        Both are complicated by non-determinism. Sampling means the same task can take different paths on different runs. A single trial tells you very little, and comparing two versions requires repeated runs. Budget for that, agent evaluation is statistical, and a one-off "it worked when I tried it" is not evidence.

        In practice at Kovalent

        • Every tool re-opens the residency question. A tool call reads tenant data, and often reaches an external system. Each one is a fresh answer to where it runs and what it sees. Per the trifecta, each outbound connector is a candidate third leg.
        • A multi-agent pattern already ships in the A2A mesh. Nodes publish a manifest with a precomputed domain embedding. The originating node scores peers by cosine similarity and delegates to the best match. The peer returns a synthesized answer rather than raw passages. That is context isolation used deliberately, the parent never ingests the peer's corpus, which keeps both the token budget and the data boundary intact.
        • There is also work to expose the knowledge base as MCP tools and resources, which is the same tool-definition contract described above, standardized so external clients can call it.
        • Every tool re-opens the residency question. A tool call reads tenant data, and often reaches an external system. Each one is a new answer to "where does this run and what does it see". Per the trifecta, each outbound connector is a potential third leg. The per-stage discipline from module 03 has to be repeated per tool, not inherited.

        MODULE 05

        Evaluation and observability

        Modules 03 and 04 each ended on a measurement problem. This module is that problem taken seriously. It is where most AI projects actually fail: not by building the wrong thing, but by having no way to tell whether the thing works, or whether last week's change helped.

        Conventional software testing rests on two assumptions, and neither survives here:

        • Determinism. The same input yields the same output, so a test that passes today passes tomorrow. Sampling breaks this outright.
        • Binary correctness. A function returns the right answer or the wrong one. But "is this summary good?" has no equality operator, and reasonable people disagree.

        So you need a different discipline, in two halves, offline evaluation against fixed cases before shipping, and observability of real behaviour after. Neither substitutes for the other, and failing to distinguish them causes a lot of confusion.

        Why "it worked when I tried it" is not evidence

        Non-determinism means a single trial is a sample of size one from a distribution you have not characterized. Run it again and you may get a different result, so an anecdote cannot distinguish a real improvement from noise, and it is equally unable to detect a regression.

        The trap this creates is anecdote-driven development. Someone reports a bad output, you tweak the prompt, the bad output goes away, and you ship. What you have measured is that one input. Whether you fixed a class of problems, changed nothing, or broke three other cases is entirely unknown, and prompt changes are notorious for exactly that kind of collateral damage.

        The fix is unglamorous and non-negotiable, a fixed set of cases you run every time, so changes are compared on identical ground. Everything else in offline evaluation is detail on top of that one idea.

        Building an evaluation set

        A golden set is inputs paired with what should happen, an expected answer, required facts, passages that should be retrieved, or a rubric describing an acceptable response. Where the cases come from matters more than how many there are:

        • Real traffic. Sampled actual queries, so the set reflects what users do rather than what you imagined they would.
        • Every production failure. The highest-value source by far. A bug that reached users becomes a permanent case, which is what makes the suite a regression net rather than a snapshot.
        • Adversarial and edge cases. Injection attempts, ambiguous questions, and questions the corpus genuinely cannot answer, the last is essential for testing refusal.
        • Stratification. Group cases by category and report per category, because an aggregate score hides that you fixed billing questions and broke technical ones.

        The leakage problem, again

        Module 01's warning about test data contaminating training reappears here in a subtler form. Suppose you tune prompts by checking the eval set over and over, adjusting until the number goes up. You are now fitting to the eval set. The score rises while real performance does not, and the number becomes a measure of your tuning effort rather than of quality.

        The standard defence is a held-out set you consult rarely, alongside the development set you iterate against. If the two ever diverge sharply, trust the held-out one.

        Four ways to score an output

        Choosing the cheapest method that actually captures what you care about is the whole craft here. Ordered from most to least reliable:

        Programmatic
        Deterministic checks, exact match, valid JSON against a schema, does the generated code compile and pass its tests, does the SQL execute and return the right rows. Cheap, perfectly repeatable, and narrow. Use it wherever the task admits it, a surprising amount of "subjective" output has a checkable component hiding inside it.
        Reference-based
        Compare against a known-good answer using overlap metrics or embedding similarity. Cheap and automatic. But for open-ended generation it correlates weakly with quality. A correct answer phrased differently scores badly, and a fluent wrong one can score well.
        Model-as-judge
        A model scores the output against a rubric. Flexible, scales to volume, handles open-ended criteria no formula captures, and carries real, well-documented biases. Treated properly below.
        Human
        The ground truth everything else approximates. Expensive, slow, and itself noisy. Two competent annotators disagree more than people expect, so measuring inter-annotator agreement tells you the ceiling any automatic method could reach.

        Model-as-judge, used carefully

        Using a model to grade a model is now standard practice, and it is often misused because the judge's own reliability goes unexamined. The documented biases are consistent enough to plan around:

        • Position bias. When comparing two candidates, judges favour one position, commonly the first, regardless of content.
        • Verbosity bias. Longer, more thorough-looking answers score higher, whether or not they say more.
        • Self-preference. Judges tend to prefer text produced by themselves or their own model family.
        • Leniency. Absolute scores cluster high, so a 1–10 scale becomes a 7–9 scale and loses most of its resolution.

        What reliably helps:

        • Prefer pairwise comparison to absolute scoring. "Which of these is better?" is a far easier judgement than "rate this 1–10", and it sidesteps leniency entirely.
        • Randomize position, or evaluate both orders and discard pairs where the verdict flips, a flip is direct evidence the judge cannot actually tell.
        • Give a specific rubric with named criteria rather than asking for a general quality score.
        • Require reasoning before the verdict. A judge that must state its justification first produces more consistent verdicts than one emitting a bare number.

        Then the step skipped most often. Your judge needs its own evaluation. Label a few hundred cases by hand, measure how often the judge agrees with the humans, and report that agreement rate alongside every score it produces. Without it you have an unvalidated measuring instrument. A confident number from an uncalibrated instrument is worse than no number, because it stops the search.

        Observability: what offline evaluation cannot tell you

        A passing eval suite says your system handles the cases you thought of. Production supplies the ones you did not, and three forces guarantee the gap widens:

        • Distribution shift. Real inputs differ from your curated set, messier, more ambiguous, and shaped by what users discover the system can do.
        • The long tail. Most volume is routine. Most failures live in rare cases, individually too infrequent to appear in any set of a few hundred.
        • Drift. Covered below, and the one that surprises teams.

        Traces are the primitive that matters

        Classic observability rests on logs, metrics, and traces. For these systems the third is disproportionately important, because a single user request fans out into many steps and an aggregate number cannot tell you which one went wrong.

        A trace records one request as a tree of spans, the retrieval call, each model call, each tool invocation, each peer request. Per span you want inputs and outputs, the model and prompt version, token counts, and latency. For retrieval, you also want which documents came back with what scores. That is the difference between "the answer was wrong" and "the reranker dropped the correct passage at position four."

        For agents this is not optional. Module 04's trajectory is a trace, and without one a failed multi-step run is uninvestigable.

        Latency is a distribution, not a number

        One statistical point deserves its own treatment, because reporting it wrongly is close to universal. Response times are heavily right-skewed, a floor set by physics, and a long tail from retries, cold starts, queueing, and unusually long generations.

        On that shape the mean is misleading, pulled upward by the tail, so it describes neither the typical nor the worst-case experience. Percentiles describe what users actually get. Generate a sample below and compare them directly.

        Latency distribution: mean versus percentiles

        2,000 samples drawn live from a log-normal distribution. Percentiles are computed by nearest-rank over the actual sample.

        Bar height, how many of the 2,000 requests landed in that time bucket

        0 msresponse time, left is faster 
        Mean
         
        p50 (median)
         
        p95
         
        p99
         

        Two lessons fall out of that. The first is that the mean hides the tail. An SLO written against an average is satisfied by a system where a substantial minority of requests are far slower than the number suggests. The second is that the tail is where users churn. p99 looks like a rounding error. At scale it is thousands of requests a day, and a user making ten calls is very likely to hit it at least once.

        What to watch in production

        In production there is no ground truth, nobody labels live traffic, so quality has to be inferred from proxies. Worth separating into three layers,

        LayerSignalsWhat a change means
        System Latency percentiles, error rate, throughput, cost per request, token counts Straightforward operational health, and the only layer with unambiguous numbers
        Pipeline Retrieval score distributions, refusal and admission rate, empty-result rate, rerank score spread, agent step counts, tool error rate, loop termination reasons The most actionable layer. A rising refusal rate means the corpus stopped covering what people ask. A rising step count means agents are working harder for the same result
        User Explicit feedback, regeneration rate, conversation abandonment, escalation to a human, citation click-through Closest to real quality, and the noisiest, explicit feedback has severe selection bias, since annoyed users rate far more often than satisfied ones

        Watch distributions and rates over time, not single values. The shape moving is the signal.

        Drift

        Three kinds, with different causes and different detection:

        • Input drift. Users ask about new things, a product launched, a policy changed, a competitor appeared. Detect it by tracking the distribution of query embeddings, not just volume.
        • Corpus drift. Documents are added, edited, and deleted. Retrieval quality can degrade because the corpus changed while the system stayed identical.
        • Model drift. The most insidious, and unique to hosted models, your provider updates the model beneath you. Nothing in your code changed, no deploy happened, and behaviour shifted. This is the strongest argument for pinning model versions where possible, and for running the eval suite on a schedule rather than only on deploy.

        Telemetry as tenant content

        Observability wants to capture prompts and completions, because that is what makes a trace useful. But a prompt containing retrieved passages is the tenant's confidential document, and a trace store holding it inherits that classification. It is the same argument module 03 made about embeddings, applied to logs.

        It is easy to build a rigorous residency story for the primary data path and then quietly ship the same content to a third-party observability vendor in another jurisdiction. Practical approaches. Log metadata rather than content by default: document ids, scores, token counts, timings. Those diagnose most problems. Sample content-bearing traces at a low rate, with explicit consent, and redact before export. Or keep full traces inside the tenant boundary and export only aggregates.

        Two more. Retention is a liability, because trace stores are long-lived aggregations of sensitive text and are rarely as well-protected as the primary store. Logs are also read by humans and by tools, so a log viewer that renders content is one more place injected instructions can land.

        Closing the loop

        Evaluation and observability are one system, not two. Production surfaces a failure. The failure becomes a permanent eval case. The case guards the fix forever. A team that does this consistently accumulates an asset competitors cannot copy, because the suite encodes everything that has ever gone wrong for real users.

        Two deployment practices make the loop safe to run quickly:

        • Shadow evaluation. Run the candidate alongside production on real traffic, serving only the incumbent's output while comparing both. Real distribution, zero user risk.
        • Staged rollout. Release to a small share and watch the pipeline and user layers before widening. Because per-request quality is unobservable, you are watching rates and distributions shift, which needs enough traffic and enough time to be more than noise.

        One caution carried from module 04, because outputs are non-deterministic, comparing two versions is a statistical exercise. Sample sizes have to be large enough that a difference is distinguishable from variance, and a single side-by-side that looks better is not a result.

        In practice at Kovalent

        • Accuracy is treated as something to measure before it is claimed. A single score answers far less than its direction across many commits. What matters is a fixed set of cases, run the same way every time, with the results kept and compared.
        • The dependency direction is the point. A public accuracy claim is downstream of the measurement that supports it, never ahead of it.
        • The A2A mesh already emits live, non-blocking telemetry per peer interaction (peer selected, answer returned), which is a trace in the sense above. Non-blocking matters, observability that can stall or fail a request has become a reliability risk rather than a safety net.
        • Because the pipeline runs on tenant nodes, telemetry is where the residency line is easiest to cross by accident. Mesh telemetry today carries routing metadata rather than chunk text, which is exactly the distinction the warning above is about. Note the precise status though. That is what the current call sites happen to send, not something the type system prevents, because the telemetry payload has an open-ended metadata field. A reviewer should read it as current behaviour rather than as an enforced guarantee.
        • The three layers above are worth exposing to the tenant, not only to the operator. A containment claim that only its author can verify is weaker than one the customer can check for themselves.

        MODULE 06

        Private networks: WireGuard and what it does not do

        Different subject, same discipline, understand the primitive, then understand precisely where its guarantees stop. Most security incidents live in that gap.

        Start with the threat model

        "Secure" is meaningless without saying against whom. For traffic between two machines over networks you do not control, the standard adversary can:

        • Read what passes, the confidentiality problem.
        • Modify it in flight, the integrity problem.
        • Impersonate either end, the authenticity problem.
        • Replay a captured valid message later, a distinct problem, since a replayed message is authentic.
        • Observe metadata: who talked to whom, when, how much. Encryption does not hide this, and it is often enough.

        A protocol should be judged on which of these it addresses, and which it leaves to you.

        The primitives

        Symmetric encryption
        One shared key encrypts and decrypts. Fast. The hard part is not the algorithm. It is how both parties came to hold the same key.
        Asymmetric encryption
        A keypair, a public key that can be published, a private key that never leaves the machine. Slower, so it is used to establish trust and agree on a symmetric key, not to encrypt bulk traffic.
        Diffie-Hellman
        Two parties who have never met derive a shared secret over a public channel, such that an observer who saw every message cannot compute it. This is the idea that makes the open internet workable.
        AEAD
        Authenticated Encryption with Associated Data, confidentiality and integrity in one operation. Historically these were separate and combining them by hand went wrong repeatedly, so modern designs fuse them.
        Nonce
        A number used once per key. Reusing one with the same key is catastrophic. It can leak plaintext outright. Much protocol design is nonce bookkeeping.
        Forward secrecy
        Session keys are ephemeral and discarded, so compromising a long-term key later does not decrypt traffic captured earlier. This is the property that defeats "record now, decrypt later."

        What a VPN actually is

        A VPN encapsulates. It takes an entire network packet, encrypts it, and carries it as the payload of another packet. To everything in between, you are sending opaque blobs between two endpoints. To the machines at each end, there is a virtual network interface behaving like an ordinary one.

        The layer matters. TLS protects one connection, and the application must implement it. A VPN operates at the network layer and protects everything, including protocols with no security of their own. That is why "put it on the private network" is a real security control. A database speaking an unauthenticated wire protocol is exposed on the open internet, and unreachable inside a mesh.

        WireGuard's design choices

        WireGuard is roughly 4,000 lines of code, against hundreds of thousands for the protocols it replaces. That is a deliberate security argument, a codebase small enough to be audited completely has fewer places for a flaw to hide.

        One precision worth carrying, because it applies directly to our own stack. The 4,000-line figure describes the Linux kernel implementation. There are also userspace implementations, notably the Go one that Tailscale ships, and those are larger and have their own performance profile. So the auditability argument is strongest as a claim about the protocol's design, which is genuinely small and rigid. It is weaker as a claim about whatever binary you are actually running. Check which implementation is in your data path before repeating the number.

        Fixed cryptography, no negotiation

        Older protocols negotiate which algorithms to use, for interoperability and future flexibility. That flexibility is also an attack surface. Downgrade attacks push both sides onto the weakest mutually-supported option, and much of TLS's painful history lives here.

        WireGuard makes the choice at design time, with no negotiation at all. It uses Curve25519 for key agreement, ChaCha20-Poly1305 for authenticated encryption, BLAKE2s for hashing, and HKDF for key derivation. Nothing to downgrade to. Upgrading means a new protocol version, which is the honest way to pay that cost.

        Cryptokey routing: the central idea

        This is the concept worth taking away. In WireGuard, a peer's identity is its public key. There are no usernames, passwords, certificates, or certificate authorities. Configuration is a short list, for each peer, its public key and the IP addresses it is allowed to use.

        That single table does double duty:

        • Outbound: a packet's destination address selects which peer's key encrypts it.
        • Inbound: a packet decrypted with a peer's key is accepted only if its source address is one that peer is permitted to claim. Otherwise it is dropped.

        Routing and authorization become the same table, so it is structurally impossible for them to disagree. Compare the usual arrangement, where routing lives in one system and access rules in another, and drift between them is a standing source of incidents.

        Silence as a feature

        WireGuard runs over UDP and never replies to a packet it cannot authenticate. No error, no reset, no response. A port scanner sees nothing distinguishable from a closed port, so the interface does not advertise its existence to anyone lacking a valid key. Under load it can also require a returned cookie before doing expensive cryptography, so an attacker cannot cheaply force the server into heavy work.

        Roaming

        A peer's endpoint address is not fixed configuration. When an authenticated packet arrives from a new address, WireGuard updates where it sends replies. Because the update requires a valid authenticated packet, an attacker cannot redirect a tunnel by spoofing a source address. The practical result, connections survive switching from Wi-Fi to cellular without renegotiating.

        The four things WireGuard leaves to you

        Now the important part. WireGuard secures a tunnel between peers that already know each other's public keys and addresses. Everything required to reach that state is out of scope by design:

        • Key distribution. How does a new machine learn every peer's public key, and how are keys rotated or revoked? Fine to do by hand for three servers. Unworkable for three hundred that come and go.
        • NAT traversal. Most machines have no publicly reachable address. Two peers behind separate home or corporate networks cannot simply connect.
        • Authorization policy. WireGuard enforces which addresses a key may claim, not which services a peer should be allowed to reach. Any expression of "the finance node may reach the reporting node but not the build cluster" lives above it.
        • Naming. There is no service discovery. You address peers by IP.

        Building those four things is building a coordination plane, and this is exactly what Tailscale, Headscale, Nebula, and similar systems sell. The architecture they all converge on is worth noticing,

        A central service distributes keys, identity, and policy. The encrypted traffic flows directly between peers and never through it. Coordination is centralized because it is small, stateful, and needs a global view. Data movement is decentralized because it is large, latency-sensitive, and the fewer parties that touch it the better.

        NAT traversal, since it is where the difficulty actually lives

        Network Address Translation lets many devices share one public address. The router rewrites outbound packets and remembers the mapping so replies find their way back. It works because connections are initiated from inside. Inbound connections to a device that has not spoken first have no mapping and are dropped.

        If both peers are behind NAT, neither can initiate. The workaround is hole punching:

        • Discovery (STUN). Each peer asks a public server what its address looks like from outside, learning the public address and port its NAT assigned.
        • Exchange. The coordination service passes each peer the other's observed address.
        • Simultaneous send. Both send to the other at the same moment. Each side's NAT sees an outbound packet, creates a mapping, and therefore accepts the incoming one. Both mappings open at once and a direct path exists.

        This fails against symmetric NAT, which assigns a different external port per destination, making the port each peer was told useless for the other. The fallback is a relay. Both peers connect outbound to a public server that forwards between them.

        The security question to ask of any relay is what it can see, and for a well-designed overlay the answer is ciphertext only. The encrypted session is established end to end between the peers. The relay forwards sealed packets it cannot open. That is what makes relaying an acceptable performance fallback rather than a containment hole.

        Zero trust: the layer above the tunnel

        Traditional security models are perimeter-based, authenticate at the boundary, and treat everything inside as trusted. It fails badly, because one compromised host inside the perimeter inherits that trust.

        Zero trust discards the assumption. Every request is authenticated and authorized on its own merits, regardless of where it came from. The maxim worth memorizing, being on the network is not the same as being allowed.

        Which is why a private mesh should never be the only control. A mesh gives you encryption and cryptographic peer identity, real, valuable properties. It does not tell a service whether this peer may perform this operation. One misconfigured policy rule is then sufficient for a breach. Defense in depth wants an independent application-layer check, so that an error in one layer is contained by another.

        In practice at Kovalent

        • Nodes join a Tailscale mesh, with WireGuard for the data path and Tailscale supplying the four missing pieces, key distribution, NAT traversal, ACLs, and naming.
        • Node addresses sit in the CGNAT range (100.64.0.0/10), which is not routable from the public internet. "No public ports on the data plane" is a factual description of the address space, not a firewall rule that could be misconfigured away.
        • Peers carry tags rather than fixed addresses, and policy is written against tags, so rules survive nodes being created and destroyed, which they constantly are.
        • Relay fallback sees ciphertext only, as above.
        • Peer-to-peer calls are then authenticated again at the application layer. The origin must be in the mesh range, and an identity lookup confirms the caller's tenant tag. Every request also carries an HMAC signature over timestamp, nonce, method, path, and body. Nonces are single-use, which defeats replay, and signing fails closed if it is enabled without a key. Concretely, a single wrong ACL entry is not sufficient to reach tenant data.
        • The dependency on a commercial coordination service is tracked with a documented exit path to self-hosted Headscale, worth doing for any vendor sitting on a critical path.

        MODULE 07

        Building the mesh, node by node

        Module 06 covered the tunnel between two peers that already know each other. This module covers the part that is actually hard at scale, which is everything that has to happen before those two peers know anything at all.

        The setup is concrete. You have machines scattered across places you do not jointly control. There is a dedicated cloud instance, a pod on a shared cluster, a workstation in an office, and a laptop on hotel Wi-Fi. You want them to reach each other, discover what each one offers, and refuse everyone else. None of that is in the tunnel protocol.

        Enrollment, step by step

        Joining one node to a mesh is six distinct operations, and each is a place to get it wrong.

        Generate keys
        The node creates its own keypair locally. The private key never leaves the machine and is never transmitted, not even to the coordination service. If a design ever asks a central service to generate or hold node private keys, that service can impersonate every node in the mesh.
        Prove it belongs
        The new node has a public key and no reputation. It authenticates with a pre-issued credential, usually a short-lived auth key, or by an operator approving the device out of band. The credential should be single-use, expiring, and pre-scoped to the tags the node is allowed to claim.
        Receive identity
        The coordination service assigns a stable mesh address and a name, and records the node's tags. The address is private-range and unroutable from the internet, so the node gains reachability without gaining exposure.
        Receive policy
        The node is told which peers it may talk to and which may talk to it, along with those peers' public keys. This is the step that makes the mesh a mesh rather than a list of unrelated tunnels.
        Connect
        Direct connections are attempted peer to peer with the NAT traversal from module 06, falling back to an encrypted relay when hole punching fails.
        Stay enrolled
        Keys expire, policy changes, nodes are revoked. Enrollment is a continuous relationship rather than a one-time event, which is why an expiring key can take a healthy node offline at an inconvenient hour.

        Why policy is written against tags

        The instinct is to write rules about addresses. That fails immediately in any environment where nodes are created and destroyed, because the rules describe a topology that no longer exists.

        Tags fix this by making policy describe roles. A node is stamped at enrollment time with what it is and who it belongs to, and rules are written against those labels. A node created ten minutes from now inherits the correct policy the moment it claims its tags, with no rule edit anywhere.

        The critical property is that a node cannot choose its own tags. Tag ownership is granted by the credential it enrolled with. If a node could assert its own tags, every rule written against them would be a suggestion.

        The failure that matters

        Now the part worth dwelling on. Policies are additive, and rules accumulate. A tenant-scoped rule written carefully in one place can be silently widened by a broad rule added somewhere else, often years earlier, often labelled legacy.

        Nothing errors. Both rules are valid. The effective policy is their union, and the union is as permissive as the loosest rule in it. This is why a mesh needs its reachability audited as a whole rather than reviewed rule by rule.

        The lab below computes that union. Toggle rules and watch the matrix.

        Mesh reachability lab, what your rules actually permit

        Six nodes across three tenants. Rules are additive, so effective reachability is their union. Computed live.

        Policy rules, click to toggle

          Who can reach whom

          Reachability is not authorization

          Everything above decides which packets arrive. It decides nothing about what the receiving service should honour, and conflating the two is the most common architectural mistake in private-network designs.

          A node that can be reached still has to decide whether the caller may perform the operation. That is why the guards from module 06 sit on top of the transport rather than inside it. The right question about a mesh is not "is it private" but "what happens when one rule in it is wrong."

          Discovery, or how nodes learn what peers know

          Connectivity gets packets between machines. It does not tell a node which peer is worth asking. With three nodes you can ask all of them. With thirty that is thirty times the cost for one answer, so the mesh needs a routing signal.

          The approach from module 04 applies directly. Each node publishes a short manifest describing its domain, along with a precomputed embedding of that manifest. An asking node embeds the query, scores every peer manifest by cosine similarity, and delegates to the best match. Module 01's geometry, used for routing rather than retrieval.

          Two properties make this work. Manifests are small, so publishing them costs nothing. They describe a domain rather than exposing its contents, so discovery leaks nothing a peer would not volunteer.

          What happens when a node leaves

          Departure deserves as much design as arrival, and usually gets none.

          • Revoke the identity so the key can no longer authenticate. Until this happens the node is still a member.
          • Remove it from peer sets, or other nodes keep attempting connections to something that will never answer.
          • Decide what happens to its data. A node that held a shard of the tenant's knowledge takes that shard with it. Either it was replicated, or the mesh just lost it.
          • Keep the audit record. The node is gone, but the history of what it did is not disposable.

          The middle item is the one that surprises people. In a mesh where each node owns its own store, removing a node is a data deletion event, and it needs to be as deliberate as any other.

          In practice at Kovalent

          • Nodes enroll with a short-lived, pre-tagged auth key minted per provision. The key carries the tags the node is allowed to claim, so a node cannot promote itself.
          • Every node is stamped with two tags. One is generic, identifying it as an agent node. The other is a per-tenant tag derived from the owner's client id. Policy is written against the tenant tag.
          • Peer sets are injected by the control plane rather than discovered ambiently. A node can only ever route to verified members of its own tenant mesh.
          • Reachability is never the only control. The application-layer guards above run on every peer call regardless of what the network policy permits, so a policy mistake alone is not sufficient to read another tenant's data. That is the defense in depth this module argues for, and the reason a mesh is audited as a whole rather than rule by rule.

          MODULE 08

          Designing a system with all of it

          The concepts now combine. Suppose you must build a system that answers questions over an organization's confidential documents. That organization has regulatory obligations about where its data lives and who can see it. Every module contributes a constraint.

          The four questions that determine an architecture

          Question 1, where does data rest?

          Documents, chunks, embeddings, and conversation transcripts are all tenant content, including the embeddings, per module 03's inversion note. "Where does it rest" has a specific answer for each, and they are frequently different by accident rather than by decision.

          Question 2, where does each compute stage run?

          Module 01 gave the rule that makes this a security question rather than a performance one. Every stage that scores or generates from text must read that text. Embedding reads the document. Reranking reads the passage. Generation reads the retrieved context. So the machine running each stage is a machine that sees tenant content. A residency claim is only as strong as its weakest stage.

          This is why a per-stage map is worth more than a box diagram. "Our architecture is private" is not checkable. "the reranker executes on this machine, in this jurisdiction, under these credentials" is.

          Question 3, who holds the keys?

          If the provider can decrypt tenant data unilaterally, then tenant data is available to the provider's subpoenas, insiders, and breaches. Customer-held keys change that. They immediately raise the hard question of custody. Where does the key live, how does it rotate, and what happens when it is lost? A provider-held recovery copy is an escrow, and an escrow substantially weakens the guarantee. This is a genuinely difficult problem, not a checkbox.

          Question 4, what crosses each boundary?

          For every arrow between components, what data is on it, what protects it in transit, and what the receiving side is trusted to do. Module 06's discipline applies. Name what the mechanism guarantees and where it stops.

          Question 5, what can the system do, not just see?

          The moment tools enter the picture, containment stops being only a question about data and becomes one about capability. Module 04's trifecta is the checkable form, for each workflow, does it combine private data, untrusted content, and an outbound channel? Tools inherit nothing from each other. Every one is a fresh answer to where it runs, what it reads, and what it can reach. So the per-stage discipline from question 2 has to be repeated for each tool.

          The design space

          PatternData at restStrengthCost
          Pooled multi-tenantProvider database, rows tagged by tenantCheapest per tenant. One system to operateOne query-scoping bug exposes everyone. Hard to evidence isolation
          Isolated per-tenantA store dedicated to each tenantIsolation is structural, not a WHERE clauseMore infrastructure per tenant, and noisy at small sizes
          Customer-premiseInside the customer's own environmentStrongest containment. Satisfies strict residency rulesDeployment and upgrades across environments you don't control
          Brokered computeData local. Heavy inference called out under the customer's own accountAvoids per-tenant GPU cost while keeping data localAn external dependency to contract, monitor, and explain

          These compose, the usual answer mixes them by workload and by tier.

          One trap worth naming, because it is common, tier-conditional guarantees. If a containment property holds only for paying customers, the public claim needs an asterisk. The free tier is usually the first thing an evaluator touches, and it is what quietly contradicts the marketing. Making the guarantee uniform and selling capability on top of it is generally both simpler to explain and easier to defend.

          Failure modes to design against

          • The guarantee that holds in one direction. Writes go to the isolated store. A read path still queries the old central one. The property is now half-true, which is indistinguishable from false in an audit.
          • The silent fallback. A component fails and the system quietly degrades to a path with weaker containment. Failing closed is nearly always correct here, an error is recoverable, a silent boundary violation is not.
          • Documentation ahead of implementation. A policy that states as fact something the runtime does not yet do. Nothing in CI catches it, and the gap is only discovered by someone with an incentive to find it.
          • Claims that outrun measurement. An accuracy claim without a golden set behind it. Build the measurement first. The claim is downstream of it.
          • Telemetry that quietly crosses the boundary. A rigorous residency story for the primary data path, undone by traces carrying prompts and retrieved passages to a third-party vendor elsewhere. Per module 05, the trace store inherits the classification of what it records.
          • Drift between mirrored implementations. Two copies of the same logic in separate deployables will diverge. Shared tests are what keep them honest.
          • Capability added without re-review. A tool shipped into an existing agent can complete a trifecta that was previously incomplete. The dangerous change is often the innocuous-looking one, the connector that only fetches.

          In practice at Kovalent

          Kovalent is one set of answers to those four questions. A managed control plane holds accounts, billing, and node lifecycle. A per-tenant node holds the knowledge base, transcripts, and every pipeline stage that reads chunk text. The two are joined by the WireGuard mesh from module 06, so the tenant side needs no public ingress at all. The control plane sends a question, a system prompt, and a query vector, and receives a finished answer.

          Two decisions are worth extracting as general lessons. Containment is uniform across tiers, including the free one. Paid tiers buy capability (reranking, citations, audit, in-tenant inference, multi-node federation), not a private place to keep documents. Default generation is brokered under the tenant's own cloud account, rather than running a model per tenant. Module 02's measured memory footprint made per-tenant inference an opt-in mode rather than an affordable default.

          EXERCISE

          Build JARVIS

          A closing exercise, and a genuinely useful one. Tony Stark's JARVIS is a familiar specification that almost everyone already holds in their head. That makes him an unusually good test of whether the last eight modules actually stuck.

          The exercise is to take him apart. For each thing he does, name the concept, decide whether it is shipped technology, active research, or fiction, and then say what it would cost to contain. The answer is more interesting than it first looks. A surprising amount of JARVIS is buildable today, and the parts that are not are rarely the parts people expect.

          Decomposing the character

          Strip the personality and JARVIS is seven capabilities stacked on each other.

          He converses
          Speech recognition into a language model into speech synthesis. Entirely shipped. This is the part that felt most magical in 2008 and is now the least remarkable thing in the stack.
          He knows the Stark corpus
          "Pull up the schematics for the Mark IV." That is retrieval over a private corpus, module 03, and the interesting part is that nobody would fine-tune the suit designs into the weights. They change constantly, need attribution, and must be deletable. Retrieval, for exactly the reasons in the fine-tuning comparison table.
          He acts on the world
          Running diagnostics, sealing the lab, flying a suit. Tool calling, module 04. He emits a structured request and a harness decides whether to honour it. Every safety property lives in that harness.
          He works overnight unsupervised
          "Run the simulation until it converges." A long-horizon agent loop with real actuators. This is where the arithmetic from the reliability lab becomes the whole problem, and it is the least solved capability in the stack.
          He remembers across years
          Persistent memory retrieved selectively, not an infinite context window. Module 04's long-term memory, which is module 03 pointed at his own history.
          He is everywhere
          The mansion, the workshop, the suit, the jet. This is module 07 exactly. JARVIS is not one machine, he is a mesh with a coordination layer and wildly heterogeneous nodes.
          He obeys Tony specifically
          Identity and authorization, and the single hardest requirement in the list. Everything else is engineering.

          The mesh problem, worked

          Take the fourth and sixth capabilities together, because that is where this gets architecturally real. A suit in flight over the Pacific, a workshop rig with serious compute, and a phone in Tony's pocket are three nodes with almost nothing in common.

          The workshop node has the corpus and the compute. The suit has hard latency limits, intermittent connectivity, and a power budget. The phone has neither compute nor storage worth using. A design that routes every suit query back to the workshop fails the moment the link drops, which is precisely when the suit needs an answer most.

          So the suit must carry a small local model and the subset of the corpus that matters in flight, and degrade to local-only operation when the mesh partitions. That is not a JARVIS problem. It is the standard edge-node problem, and module 07 gives the same answer. Enroll every node with a scoped identity, publish what each one can do, and route by capability. Design the partition case first, because it is the case that happens.

          JARVIS is the lethal trifecta with a British accent

          Run him against module 04's three conditions and he does not merely satisfy them, he maximizes each one.

          • Private data. Every Stark Industries design, financial record, and personal communication.
          • Untrusted content. He reads the news, parses intercepted transmissions, and ingests telemetry from hostile environments. All of it is attacker-influenceable text.
          • External capability. He does not merely send email. He flies weaponized aircraft.

          This is not a hypothetical in the source material either. The plot of Age of Ultron is, stripped of costumes, an alignment and containment failure in a system with unrestricted capability and no meaningful harness. Tony builds an agent whose tools include manufacturing and networking, gives it an underspecified objective, and it optimizes for the objective as stated. That is a well-documented failure mode, not a plot device.

          The exercise: which leg would you break, given that the fiction refuses to break any of them? There is no comfortable answer, which is the point. Every real deployment of a capable agent is a negotiation about which of the three you are willing to give up.

          "Override, authorization Stark"

          The voice-authentication trope deserves a closer look. It is the security design most often copied from fiction into real products, and it is close to the worst option available.

          A spoken passphrase is a shared secret transmitted in the clear, in a room, repeatedly, in front of anyone present. It is replayable by recording. Voice timbre is not a secret either, since it is published in every interview he has ever given. As an authentication factor it fails on secrecy, on replay resistance, and on revocation, which is the full set.

          What the fiction is reaching for is what module 07 calls scoped identity. The real version is a hardware key Tony physically holds. Authorization is per capability, rather than one single override. Irreversible or outward-facing actions require a fresh confirmation, regardless of who is asking. Which is, unavoidably, less cinematic.

          Scoring the fiction honestly

          This is the part worth being disciplined about, because the interesting line is not between "possible" and "impossible."

          CapabilityStatusWhat actually blocks it
          ConversationshippedNothing. This is a solved product problem.
          Retrieval over a private corpusshippedNothing conceptual. Chunking and evaluation are the real work.
          Tool callingshippedNothing. The hard part is deciding what to permit, not how to call it.
          Mesh across heterogeneous nodesshippedEngineering effort, not invention. Module 07 is a build, not a research programme.
          Long-term memorypartialStoring is easy. Deciding what is worth remembering, and what to forget, is unsolved.
          Multi-hour autonomous workresearchCompounding error. At 99% per step a 200-step task succeeds 13% of the time, and physical actions often cannot be retried.
          Real-world robotic manipulationresearchPerception and control in unstructured environments. Far behind the language stack.
          General reasoning across novel domainsfictionModule 01's narrowness. No deployed system transfers skill to genuinely new tasks.

          The gap between JARVIS and a buildable assistant is reliability and autonomy, not conversation.

          Read the table again and notice where the line falls. Four of the eight rows ship today. What separates a real assistant from JARVIS is not that he talks well. It is that he can be trusted to work unsupervised for eight hours on something that matters, and then be held to account for what he did. Both of those are containment and reliability problems, which is where seven of the eight modules have been pointing the whole time.

          The version you could actually build

          • Mesh. Workshop node with the corpus and compute, suit node with a quantized local model and a cached working subset, phone as a thin client. All enrolled with scoped identities, all routing by published capability.
          • Knowledge. Retrieval with citations and a refusal threshold, so "I do not have anything on that" is a first-class answer. In a workshop that is a feature, not a limitation.
          • Actions. Read-only tools open. Anything irreversible or outward-facing behind a hardware-key confirmation. No single override that unlocks everything.
          • Autonomy. Bounded step budgets, checkpoints a human approves, and full trajectory logging. Not eight unsupervised hours.
          • Containment. The workflow that ingests untrusted external content gets no outbound capability at all. That is the leg you break.

          The result is genuinely useful and noticeably less dramatic than the films. That gap is the honest summary of where this technology currently sits.

          FINAL CHECK

          Across the modules

          Ten questions that require holding two or more concepts at once, the kind of reasoning a real design review asks for.

          REFERENCE

          Where these claims come from

          A learning resource that cannot be checked is just an assertion. These are the primary sources behind the load-bearing claims in each module. They are listed so you can go past the summary, and so a future reader can verify rather than trust. Treat them as pointers to look up rather than as a formatted bibliography, and correct the entry if you find a detail wrong.

          Module 01
          Goodfellow, Bengio and Courville, Deep Learning, for gradient descent and backpropagation. Mikolov et al. on word2vec, for the distributional hypothesis turned into geometry. Reimers and Gurevych, Sentence-BERT, for the bi-encoder and cross-encoder split and why the cheap one has to come first.
          Module 02
          Vaswani et al., Attention Is All You Need, for the transformer and multi-head attention. Sennrich et al. on byte-pair encoding for subword tokenization. Ouyang et al., InstructGPT, for the pretrain, instruction-tune, preference-tune sequence and where sycophancy enters. Liu et al., Lost in the Middle, for position effects in long contexts.
          Module 03
          Lewis et al. for the original retrieval-augmented generation formulation. Robertson and Zaragoza, The Probabilistic Relevance Framework, for BM25. Malkov and Yashunin for HNSW. Cormack, Clarke and Buettcher for reciprocal rank fusion, which is where the constant 60 comes from. Morris et al., Text Embeddings Reveal (Almost) As Much As Text, for the embedding inversion result that makes a vector store confidential.
          Module 04
          Yao et al., ReAct, for interleaved reasoning and acting. Simon Willison's writing on prompt injection and on the lethal trifecta, which is where that framing comes from. Anthropic's Building Effective Agents for when to prefer one agent over several. The Model Context Protocol specification for the tool and resource contract.
          Module 05
          Zheng et al., Judging LLM-as-a-Judge with MT-Bench and Chatbot Arena, for the position, verbosity and self-preference biases and for pairwise comparison as the mitigation. Google's Site Reliability Engineering on why latency is reported as percentiles and how to write an SLO against a distribution.
          Module 06
          Donenfeld, WireGuard: Next Generation Kernel Network Tunnel, the original paper, for cryptokey routing and the fixed cipher suite. The Noise Protocol Framework specification for the handshake WireGuard builds on. Tailscale's published write-up on NAT traversal for hole punching and relay fallback. RFC 6598 for the shared address space that 100.64.0.0/10 comes from.
          Module 07
          Tailscale's documentation on auth keys and ACL tags, for enrollment and for policy written against roles rather than addresses. Saltzer and Schroeder, The Protection of Information in Computer Systems, for least privilege and complete mediation, which is the formal statement of this module's argument that every call gets checked no matter which packets the network permits. NIST SP 800-207, Zero Trust Architecture, for reachability and authorization being separate decisions.
          Module 08
          This module recombines the ones above, so their sources carry most of it. What is new here: AWS's published guidance on SaaS tenant isolation, for the pooled and siloed ends of the design-space table and what each one costs to evidence. Shostack, Threat Modeling: Designing for Security, for the per-boundary discipline question 4 asks for. NIST SP 800-57, Recommendation for Key Management, for the custody, rotation, and recovery problems that question 3 raises without solving.

          REFERENCE

          Glossary

          Agent
          A loop around a model with tools attached, the model requests a function call, the harness executes it and appends the result, and the model reads again until it stops asking.
          AEAD
          Authenticated Encryption with Associated Data. Confidentiality and integrity in a single operation, rather than two that must be combined correctly by hand.
          ANN
          Approximate Nearest Neighbour. Trades exactness for speed in vector search. The approximation is real and tunable.
          Auth key
          A short-lived, single-use credential a new node presents to join a mesh. Pre-scoped to the tags that node may claim, so it cannot promote itself.
          Attention
          The mechanism letting every position in a sequence look directly at every other, via query/key/value vectors. Quadratic in sequence length.
          Backpropagation
          Efficient computation of the loss gradient for every parameter in one backward pass, using the chain rule.
          Bi-encoder
          Embeds each item independently, so vectors can be precomputed and compared cheaply. The recall stage.
          BM25
          Lexical ranking function, term frequency with diminishing returns, inverse document frequency, and length normalization.
          BPE
          Byte-Pair Encoding. Builds a subword vocabulary by repeatedly merging the most frequent adjacent pair.
          ChaCha20-Poly1305
          WireGuard's AEAD cipher. Fast in software without hardware acceleration.
          Chunking
          Splitting documents before embedding. Size, overlap, and boundary choice dominate retrieval quality.
          Context window
          The maximum tokens a model can attend to at once. A hard architectural limit, not a preference.
          Compaction
          Summarizing earlier turns to reclaim context space. Lossy by definition, and what it drops is chosen without knowing what will matter later.
          Confused deputy
          A component acting on a user's behalf with authority the user does not have, an agent holding broad service credentials retrieving what the requester could not.
          Corpus drift
          Retrieval quality degrading because the documents changed, while the system itself stayed identical.
          Cosine similarity
          Similarity as the cosine of the angle between two vectors, ignoring magnitude. A dot product when vectors are unit-normalized.
          Cross-encoder
          Scores a (query, passage) pair read together. More accurate than a bi-encoder, and impossible to precompute. The precision stage.
          Cryptokey routing
          WireGuard's core idea, a peer's public key is bound to the addresses it may use, making routing and authorization one table.
          Curve25519
          The elliptic curve WireGuard uses for Diffie-Hellman key agreement.
          Diffie-Hellman
          Deriving a shared secret over a public channel such that an eavesdropper cannot compute it.
          Effective policy
          The union of every enabled rule in a mesh. As permissive as its loosest member, which is why reachability is audited as a whole rather than rule by rule.
          Embedding
          A vector representation where geometric proximity encodes semantic similarity. Not comparable across models.
          Forward secrecy
          Ephemeral session keys, so a later long-term key compromise cannot decrypt earlier captured traffic.
          Golden set
          Curated questions with their expected retrievals and answers. The basis of any defensible accuracy claim.
          Held-out set
          Eval cases consulted rarely, so that iterating against a development set cannot quietly fit the measurement itself.
          Hallucination
          Fluent, confident, fabricated output. Structural, the objective rewards plausibility, and no internal "I don't know" signal exists.
          HNSW
          Hierarchical Navigable Small World. Layered proximity graph enabling logarithmic approximate vector search.
          Hole punching
          Getting two NATed peers to send simultaneously so each NAT opens a mapping, yielding a direct path.
          Inference
          Running a trained model on new input. The weights do not change.
          KV cache
          Cached keys and values for previous tokens, so each new token is cheap. Costs memory proportional to context length.
          Enrollment
          The six steps of joining a node to a mesh: generate keys, prove membership, receive identity, receive policy, connect, and stay enrolled. A lease, not a one-time event.
          Lethal trifecta
          Private data access + untrusted content + an external communication channel. Any two is usually manageable. All three is an exfiltration path.
          Loss function
          The scalar measure of wrongness that training minimizes. Defining it defines what the system optimizes for.
          Model-as-judge
          Using a model to score another model's output against a rubric. Carries position, verbosity, self-preference, and leniency biases, and needs its own calibration against human labels.
          Model drift
          A hosted provider changing the model beneath you. No commit, no deploy, no alert, the argument for pinned versions and scheduled evals.
          NAT
          Network Address Translation. Many devices behind one public address. The reason inbound connections usually fail.
          Nonce
          A number used once per key. Reuse can be catastrophic.
          Prompt injection
          Instructions smuggled through content the model reads. Indirect injection arrives via retrieved or ingested documents.
          Percentile
          The value below which a given share of observations fall. On skewed data like latency, p50/p95/p99 describe real experience where a mean does not.
          Quantization
          Storing weights at lower numeric precision to cut memory, at gradual quality cost.
          RAG
          Retrieval-Augmented Generation. Fetch relevant passages at query time and ground the answer in them.
          ReAct
          Interleaving reasoning and acting in an agent loop, so each tool result informs the next decision rather than following a fixed plan.
          Recall@k
          Fraction of the passages that should have been retrieved which appear in the top k. Retrieval's headline metric.
          RRF
          Reciprocal Rank Fusion. Merges ranked lists by position (1/(k+rank), k usually 60), so incomparable scores never need calibrating.
          Self-supervised
          Training where labels come from the data itself. Removed the human-labeling bottleneck and enabled LLM scale.
          STUN
          A public service telling a peer how its address appears from outside its NAT.
          Temperature
          Scales the output distribution before sampling. Lower is sharper and more deterministic. A randomness control, not a quality control.
          Tool-calling
          A model emitting structured text naming a function and arguments. The model never executes anything. The harness parses, validates, and decides.
          Trace
          One request recorded as a tree of spans. The primitive that turns "the answer was wrong" into "the reranker dropped the correct passage at position four."
          Trajectory
          The path an agent took, steps, tool choices, wasted calls, recoveries. Measured alongside outcome, since an agent can still succeed while badly degrading.
          Shadow evaluation
          Running a candidate alongside production on real traffic while serving only the incumbent's output. Real distribution, no user risk.
          Span
          One unit of work inside a trace (a retrieval, a model call, a tool invocation) carrying its own inputs, outputs, and timing.
          Tag
          A role label stamped on a node at enrollment. Policy written against tags survives node churn, and tag ownership is granted by the enrolling credential so a node cannot choose its own.
          Token
          The subword unit a model actually processes. Roughly ¾ of a word in English. The unit all budgets are denominated in.
          Top-p
          Nucleus sampling. Restricts choices to the smallest set whose probabilities sum to p.
          Zero trust
          Authenticate and authorize every request on its own merits. Network position is not authorization.

          A working guide to machine learning, language models, retrieval, and private networking.
          The Kovalent asides show where each idea lands once something has to run in production. Skip every one of them and the guide still teaches the subject.
          Products move faster than the writing about them, so check anything load-bearing against the product itself.