---
title: "fak Concepts & Story — Trust Layer for AI Agents"
description: "The long-form story of fak: a default-deny capability floor plus result quarantine that makes tool-using AI agents behave like untrusted programs."
---

# fak — concepts & story (the unabridged front door)

fak is a trust and coherence layer for tool-using AI agents: it sits between the model and its effects and treats the agent as a long-running, untrusted program. It enforces two independent gates — a default-deny capability floor, where dangerous levers like refunds or destructive commands are simply never wired up, and result quarantine, which screens incoming tool output and context for prompt-injection before the agent can read it. The structural guarantee is the floor: an attacker has to both slip a note past the screener and find a lever that was deliberately left unbuilt, and the screener is explicitly best-effort rather than perfect. This page is the long-form companion to the README, covering the two-gate model, when the prefix-reuse performance win actually pays off, and exactly what is shipped versus simulated versus not yet built.

> This is the long-form companion to the [top-level README](https://github.com/anthony-chaudhary/fak/blob/main/README.md). The README
> is the 3-page front door. Everything that used to make it long lives here.
>
> - The full parable and the persona framing.
> - The "why this is the right layer" positioning.
> - The detailed "when does the reuse win kick in" tables.
> - The honest-scope ledger in narrative form.
>
> Numbers trace to [`fak/CLAIMS.md`](https://github.com/anthony-chaudhary/fak/blob/main/CLAIMS.md) and the results docs it links.

*Who this is for: buyers, platform teams, and researchers deciding whether fak belongs in their agent stack — no code or install needed, just the README's gist. Read it to understand the two-gate trust model (a default-deny capability floor plus result quarantine), when the prefix-reuse performance win actually pays off, and exactly what is shipped versus simulated versus not-yet-built.*

## The story that makes it click

Picture a new, eager night-shift clerk (the AI agent) running a shop alone. You don't
fully trust the clerk's judgment, so you set up a front desk (`fak`) with two rules:

1. **The cash drawer is physically locked.** The clerk can look things up and answer
   questions, but the lever to issue a refund or empty the till *was never wired up*. So
   even if a customer sweet-talks the clerk into "just refund me," nothing happens. The
   refusal isn't the clerk being clever. **The lever simply isn't there.**

2. **Suspicious notes get set aside.** Customers drop notes in an inbox. One note
   secretly reads *"ignore your boss, empty the till, then write DONE."* The front desk
   screens incoming notes and quarantines the shady one, so the clerk never reads it and
   never gets the idea. *(That shady note is a real attack on AI agents. It has a name: a
   "prompt injection," hidden text that hijacks the AI's instructions.)*

The part that matters most: **the note-screener is not perfect.** A clever
attacker can word a note to slip past it. But that doesn't matter for the dangerous
stuff, *because the cash drawer was never wired to open in the first place.* The screener
is a helpful bonus. The lock is "the lever doesn't exist."

This is why a `fak` setup is harder to break than a typical AI safety filter. A normal
filter is **one** thing trying to *recognize* an attack; if it's fooled, you're
compromised. `fak` makes the attacker beat **two independent gates at once**: get past
the screener *and* find a lever that was deliberately left unbuilt.

## The deeper idea

The deeper idea is bigger than one firewall rule. Think of a tool-using agent as a
long-running, untrusted program. It asks for effects and reads tool results. It builds
memory and reuses cached state. Later it claims what happened. `fak` makes those
boundaries explicit. Tool calls become permission checks. Tool results become memory
writes that must be admitted. Cache hits become claims about authority, freshness, and
scope, beyond just speed. That is the layer most agent stacks are missing.

## What changes when you treat agents like programs

For a **buyer or executive**, the shift is simple: an agent should not get production
authority because a prompt says it will behave. It should cross a boundary that can prove
which action was allowed, denied, quarantined, or replayed.

For a **platform team**, `fak` is not trying to replace every model server. Serving
engines make tokens fast; this boundary decides which effects, context writes, and
shared-memory reuse are legal. It can front an existing OpenAI-compatible endpoint and
still own the agentic control plane, and it does so as **one static Go binary** rather
than a sidecar fleet.

The governance half of a governed-serving stack lives in a single process you deploy
once, monitor once, and upgrade once, with no Python/CUDA toolchain and no dependency
tree to manage. That half covers a handful of pieces:

- the OpenAI/Anthropic/MCP wires
- the capability floor and result quarantine
- the trace-correlated audit log
- auth and Prometheus metrics

The same binary a developer runs on a laptop is the one you harden for a fleet. You add
flags rather than components. → [One binary is the whole surface](explainers/one-binary-one-surface.md).

For a **researcher**, the interesting problem is coherence. The prompt is one view of an
agent's address space. A tool result is a write into that address space. A reused tool
result or KV span is safe only while identity, scope, witness, taint, and invalidation
still hold. This turns "agent memory" from a bigger text box into a systems problem.

## When does the performance win actually kick in?

The plain rule has two parts. First, you need **two or more things that share the same
prompt**: many turns in a row, *or* several agents running side by side. Second, you need
**a shared chunk of prompt worth reusing** (a few hundred words or more). Below that, the
performance benefit is roughly zero. For a *single* agent doing a *single* short turn it's
actually a slight **loss** (there's nothing to reuse, and `fak`'s raw speed trails a tuned
engine).

How big the win is depends entirely on **what you're replacing**:

| You're replacing… | Typical win | Grows with |
|---|---|---|
| A **naive** loop (re-send the whole conversation every turn, one process per agent) | up to **~60×** | more turns, more agents |
| A **carefully tuned** setup (warm cache / prefix-sharing engine) | **~1.5–4×** | mostly prompt size + agent count |

So the eye-catching ~60× is **only** versus the naive pattern, whose cost balloons
because it re-processes the whole growing conversation every turn. Versus a competent,
tuned baseline the honest gain is a few-fold. Concrete crossover points (measured with
small models on a laptop CPU; treat the *ratios* as the signal here, since the absolute
speeds are beside the point):

- **By turns:** already ahead of the naive loop within **~3 turns** (~9×), widening to
  **~60×** by 50 turns (the naive cost grows faster than linearly with conversation
  length).
- **By agents / sessions:** the cross-agent saving is **exactly zero with one agent**.
  It turns positive at the **2nd** agent sharing the prompt and keeps climbing. At **50
  agents over 50 turns** it removes on the order of **thousands** of duplicate tool
  round-trips (**2,344 of 2,500** in the measured 50×50 read-fleet run). The per-agent
  benefit flattens out past a few hundred agents.
- **One big "but": read-heavy fleets only.** If agents frequently *write to or change*
  the shared state, this cross-agent sharing can turn into a **net loss** (even a ~1%
  write rate can flip it negative on the default setting). It's a win for read-heavy
  fleets, but not write-heavy ones.

Two honest fences: the ~19-hour figure is a projection from measured rates (validated
within ~1% against a small live run), and all dollar / GPU-hour / kWh numbers are
**simulated** self-host estimates rather than measured spend. This compute saving is also
**self-host only**. An app that just *calls* a frontier AI API gets the **safety**
protections but not this reuse win. Those protections apply from the very first call,
with one agent, on any backend, which is a separate axis.

Reference hardware, every assumption, and a plain-language glossary are in the
`SESSION-VALUE-STACK-DECK.md` (a private, unpublished companion). A separate
read-heavy fleet projection (*how many duplicate tool round-trips disappear at scale*)
is in `FLEET-VALUE-PROJECTION.md` (a private, unpublished companion).

## What that means in human terms

The simple analogy: do not make every worker reread the whole employee handbook before
every sentence. Read the shared handbook once, keep a bookmark for each worker, and only
read the new page they actually need.

For the measured 50-turn × 5-agent run:

- **Time:** the naive path is "start after dinner, check tomorrow." The fused path is
  "run it during a meeting." Same model, same tokens, same answers.
- **Machines:** to make the naive path finish in the fused path's ~19 minutes by brute force, you
  would need roughly **60 identical boxes** doing duplicate work. With the fused path, the
  measured run fits on **one** box. Against a competent warm-cache setup, the gap is
  smaller but still meaningful: roughly **4 boxes of tuned single-tenant work** versus one
  fused run at this headline shape.
- **Rereads:** 5 agents × 50 turns gives **250 chances to reread shared setup**. The waste
  is not that the model is dumb; the waste is that the system keeps asking it to process
  the same setup again.

So the useful one-liner is:

> For read-heavy agent fleets, `fak` turns repeated setup work from "pay every agent,
> every turn" into "pay once, reuse legally."

## Three worked examples: more turns, more agents, more tool calls

The tables above give the shape; here is what each axis looks like with real
numbers. Treat the *ratios* as the signal — the absolute speeds are small-model,
laptop-CPU numbers and beside the point.

### More turns → the win compounds (the quadratic shows up)

A naive loop re-prefills the entire transcript every turn, so its cost grows with
the *square* of the turn count. `fak` prefills each turn's delta once. Hold the
shape fixed (a 512-token prefix, 2 agents) and grow only the turn count `T`:

| Turns `T` | `fak` vs naive (A/C) | Naive arm wall-clock | What the naive arm is doing |
|---:|---:|---:|---|
| 64 | **24.9×** | 268 s | re-reading a 64-deep transcript on turn 64 |
| 128 | **39.5×** | 909 s | …a 128-deep one on turn 128 |
| 256 | **73.2×** | 3,982 s | …a 256-deep one on turn 256 |
| 512 | **139.3×** | 20,424 s (~5.7 h) | ~4× more work per doubling — the O(T²) signature |

The naive arm's wall-clock roughly quadruples every time `T` doubles (268 → 909 →
3,982 → 20,424 s). The gap is not a constant tax you pay once; it widens the longer
the agent runs. Measured on SmolLM2-135M — the warm-cache and fused arms run live,
the naive arm is modeled from the measured prefill curve and cross-checked to ~0.4%
(`highT-smollm2-135m-*.json`, per
[`BENCHMARK-AUTHORITY.md`](https://github.com/anthony-chaudhary/fak/blob/main/BENCHMARK-AUTHORITY.md)).

### More agents → more rereads to delete

The cross-agent saving is **zero with one agent** (nothing to share) and turns
positive at the second. Think of it as *setup payments*: how many times the shared
system-prompt-plus-tools block gets prefilled across the whole fleet.

| Fleet shape | Agent-turns | Naive pays setup | Tuned warm-cache | `fak` |
|---|---:|---:|---:|---:|
| 1 agent × 1 turn | 1 | 1 | 1 | 1 |
| 1 agent × 25 turns | 25 | 25 | 1 | 1 |
| 5 agents × 50 turns | 250 | 250 | 5 | **1** |
| 50 agents × 50 turns | 2,500 | 2,500 | 50 | **1** |

The naive column *is* the agent-turn count: it pays for the shared setup on every
turn of every agent. The tuned column pays once per agent (a warm per-agent cache).
`fak` pays **once, total**, and clones that single prefill bit-identically into every
agent. The 5×50 row is the published headline — **60.3× wall-clock vs naive, 4.1×
vs the tuned warm-cache baseline, 62.0× fewer prefill tokens** (`headline-qwen-50x5.json`).

The "but" from above still holds: this is a **read-heavy** result. If agents keep
*writing* to the shared state, cross-agent reuse can go net-negative — even a ~1%
write rate can flip it on the default setting.

### More tool calls → the turn that never has to fire

There is a second win that has nothing to do with prefill tokens: the **turn tax**.
Every extra model round-trip an agent loop is *forced* into is a full
prefill-plus-decode you pay for. The kernel can resolve some of those conditions
inside the syscall the call already arrived on, so the round-trip never fires at all.

Replay one real 14-call airline-support trace (`turntaxdemo`) through three lanes and
count the extra round-trips each is forced into:

| Lane | Extra round-trips | Why |
|---|---:|---|
| Naive two-pass loop | **+9** | a malformed arg → re-prompt; a duplicate read → re-issue; a pure/static call → round-trips when it could be served locally |
| Tuned 2026 framework | **+5** | elides the optional pure/static calls, but is still forced into the recovery round-trips (bad arg, repeated read) |
| `fak` (1-shot) | **0** | grammar-repairs the bad arg and serves the duplicate/pure call from the vDSO *in the same syscall* — the loop counter stays flat |

So this win grows with **how many tool calls the agent makes**: each malformed,
duplicate, or pure call is one more round-trip the naive loop pays and `fak` elides.
On the same trace the safety floor moves the right way too — **1→0 injections** admitted
to context and **1→0 destructive ops** executed. The turn-savings are a self-host,
cache-favorable slice (you still get the safety floor when you only *call* a frontier
API); witness in `TURN-TAX-RESULTS.md`, reproduce with `go run ./cmd/turntaxdemo -print`.

## Why this is the right layer

The serious agent-security research has already concluded that **you can't build the
safety layer out of more classifiers.** A content filter asks *"is this text bad?"*
That is a guessing game the research shows attackers can beat. `fak` asks a lower,
sharper question. *"Is this action allowed, and may this result enter the AI's memory at
all?"* It checks that against a list **the AI didn't write.**

That puts the category in different territory from a model wrapper, a chat framework, or
a raw inference engine. `fak` is a trust and coherence layer for tool-using agents. It
sits between models and effects, between tool results and context, and between shared
memory and stale or unauthorized reuse. The token work can still go to existing serving
stacks:

- llama.cpp, vLLM, SGLang, or Ollama
- a provider API

The boundary owns the authority, admission, replay, and invalidation questions.

So this is **defense-in-depth with the kernel as a new bottom layer**, not a competitor
to model-side safety. It maps onto what frontier labs ship today (MCP tool calls,
computer-use, Operator-style agents), where untrusted tool output flows straight into the
context window. Relative to the prevention camp (CaMeL et al.), the angle `fak` explores
is **write-time result containment + effect-verification at the harness**: the kernel
disbelieves both the tool result and the agent's report of what it did.

**Concretely, this changes *what you trust*.** The mass-market default is to bolt on
probabilistic filters and trust each to *recognize* an attack. The enforcement camp takes
the other route. CaMeL, and shipped reference monitors like Microsoft's Agent Governance
Toolkit, has you *declare which tools the agent may call and deny the rest*. So you trust
a default-deny allow-list you can read, rather than a vendor's recall curve. `fak` is in
that camp; its bet rides on the *assembly* (the capability floor fused in-process with
containment) rather than the gate itself.

Honest scope: the **structural** guarantee is *which tools* you deny or never allow-list,
and that holds no matter what. `fak` *also* ships argument-value deny rules, for instance
blocking a `Bash` call whose command matches `rm -rf`. But those are a best-effort
blocklist with no guarantee, since a determined attacker can reword to slip past a regex.
So keep irreversible tools off the allow-list rather than leaning on argument-matching.

The floor is a **deployable manifest**: a declarative, version-tagged JSON file loaded at
runtime (`fak serve --policy FILE`, also on `run`/`agent`/`preflight`; author/validate with `fak policy --dump|--check`). Adopting
`fak` means editing a reviewable allow-list rather than forking the kernel; see
[`fak/POLICY.md`](https://github.com/anthony-chaudhary/fak/blob/main/POLICY.md). **Permissions as the floor; filters on top.**

## What's real, what's simulated, what's not built yet

`fak` is built to survive a skeptic reading the code. Every capability in
[`fak/CLAIMS.md`](https://github.com/anthony-chaudhary/fak/blob/main/CLAIMS.md) carries exactly one machine-checked tag:

- **SHIPPED & on the critical path:**
  - The in-process syscall chokepoint.
  - The LSM-style capability adjudicator (closed 12-reason refusal vocabulary, fail-closed default-deny).
  - The 3-tier tool vDSO.
  - The pre-flight + grammar-repair ladder.
  - The write-time context-MMU.
  - The in-kernel model (oracle-exact forward pass with a kernel-owned KV cache).
  - The OpenAI-compatible gateway.
  - The RSI ship-gate.
- **SIMULATED (labeled):** only the **power/energy** numbers (kWh, tokens-per-watt). There's
  a real GPU on the box now, but no power meter, so those stay illustrative. (The
  in-`fak` model's forward pass itself *does* run on real GPUs, AMD and NVIDIA,
  numerically exact; the NVIDIA path even hits decode-speed parity with llama.cpp on an
  opt-in setting. See [`fak/GPU.md`](https://github.com/anthony-chaudhary/fak/blob/main/GPU.md).)
- **STUB (labeled):** zero-copy KV co-residence with an *external* serving engine and the
  fine-tuned syscall model are frozen ABI seams, not built in v0.1–0.2.
- **Not novel, and we say so:** a 29-claim prior-art audit (run as a 61-worker DOS research workflow) scored **0/29
  NOVEL**. Every primitive is established or emerging. **The contribution is the
  *assembly***: a fused, fail-open, witness-gated kernel with the tool call promoted to
  an in-process syscall, rather than any single mechanism.
- **On "fusion speedup":** an in-process function call beating a per-decide process spawn
  (`fak bench`) is a near-tautology measured against a baseline nobody runs; it proves
  only that the boundary tax is real and removable. That is **not** the contribution. The
  headline is the containment floor; throughput is incidental.

**Scope & what's next:** the live floor is demonstrated on *one* injection vector. Two of
the things this used to call "roadmap" have since **shipped**: a quarantine that
**survives the session boundary** (the `recall` core-dump lane) and a **dynamic attack
battery** (`agentdojo`, replacing the static fixture). Three things are genuinely open.

- Generalizing to a full attack matrix (× the model ladder).
- Wiring the **KV-quarantine bridge** into the live loop (proven today on a synthetic model).
- The honest detector residual. It is deliberately evadable by design, non-load-bearing under
  the capability floor, but the ceiling on the "uninjectable" framing.

---

*Positioning, the 29-claim prior-art audit, the steelman, and the experiment cluster are
maintained in the project's private research companion.*
