# The Context-Egress Gate: Decide What Your Agent May Send Before You Compare Free, Paid, or Self-Hosted

> Source: <https://dev.to/datago_8008/the-context-egress-gate-decide-what-your-agent-may-send-before-you-compare-free-paid-or-1a9e>
> Published: 2026-11-05 15:41:08+00:00

**Short version:** every comparison of free, paid, and self-hosted inference I have seen starts with the bill, and almost none of them start with the payload. The expensive failure is not a slow token; it is a secret that left your repository inside a prompt and nobody noticed for three weeks. So build the egress gate first, get an exit code you can defend in review, and only then argue about price.

That order matters more this month than last, because the loudest AI discussion right now is about what agents will do to our jobs, while the quieter and more actionable question is what our prompts do to our credentials. I cannot settle the first debate, but I can hand you a small script that settles the second for your own repo.

Most agent turns send far more than the sentence a developer typed: file excerpts, stack traces, config keys, sometimes environment values that were never meant to be read by a stranger. Once that context crosses a network boundary, the cost question changes shape, because the cheapest per-token option can still be the most expensive decision you make this quarter. How many teams can honestly say which files their coding agent transmitted yesterday?

I am not arguing that hosted inference is unsafe by default, and I am definitely not arguing that self-hosting is automatically compliant. I am arguing that the decision needs an input that pricing pages never provide: a count of what your workflow is willing to export. If you cannot produce that count, your free-versus-paid comparison is measuring the wrong variable.

Do this on paper first, because the table below is the artifact reviewers actually argue about. The point is not to rank vendors; it is to name the classes of content your agent touches and decide, once, what may leave.

| Data class | Example | If it leaks | Default rule | 
|---|---|---|---|
| Public snippets | open-source file you already published | nothing new | send freely | 
| Internal source | private module, no secrets | competitive exposure | redact or self-host | 
| Operational data | logs, hostnames, customer IDs | incident scope | redact, minimise window | 
| Credentials | keys, tokens, private keys | rotation + disclosure | never send | 
| Regulated data | personal or health records | legal exposure | self-host only | 

Four rows, five minutes, and a decision you can point at later when someone asks why the agent was allowed to read `deploy/` but not `.env`. Notice how quickly "which model is cheapest" becomes a much smaller question than "what is this thing allowed to see?"

The script below is deliberately boring: standard library only, no network calls, no cloud dependency, and it fails closed. It scans the files you staged in git, scores findings by severity, writes a JSON report, and returns a non-zero exit code when the payload crosses your threshold. Treat it as a starting point you are expected to edit, not a security product.

``` bash
#!/usr/bin/env python3
"""preflight.py - refuse to build a prompt from staged files that carry secrets."""
import json, math, re, subprocess, sys
from collections import Counter
from pathlib import Path

PATTERNS = {
    "private_key":   re.compile(r"-----BEGIN (RSA |EC |OPENSSH )?PRIVATE KEY-----"),
    "aws_key":       re.compile(r"AKIA[0-9A-Z]{16}"),
    "jwt":           re.compile(r"eyJ[A-Za-z0-9_\-]{10,}\.[A-Za-z0-9_\-]{10,}\.[A-Za-z0-9_\-]{10,}"),
    "generic_token": re.compile(r"(?i)(api[_-]?key|secret|token)\s*[:=]\s*['\"]?([A-Za-z0-9_\-]{16,})"),
    "email":         re.compile(r"[A-Za-z0-9._%+\-]+@[A-Za-z0-9.\-]+\.[A-Za-z]{2,}"),
}
WEIGHTS = {"private_key": 50, "aws_key": 40, "jwt": 25,
           "generic_token": 20, "high_entropy": 10, "email": 3}
HIGH_ENTROPY = re.compile(r"[A-Za-z0-9+/=_\-]{24,}")

def shannon(s):
    if not s:
        return 0.0
    n = len(s)
    return -sum((c / n) * math.log2(c / n) for c in Counter(s).values())

def staged_files():
    out = subprocess.run(
        ["git", "diff", "--cached", "--name-only", "--diff-filter=ACMR"],
        capture_output=True, text=True, check=True)
    return [Path(p) for p in out.stdout.split() if p]

def scan(paths, max_bytes=200_000):
    report = {"files": [], "findings": [], "score": 0}
    for p in paths:
        try:
            text = p.read_text(encoding="utf-8", errors="ignore")[:max_bytes]
        except OSError:
            continue
        report["files"].append(str(p))
        for rule, rx in PATTERNS.items():
            for m in rx.finditer(text):
                report["findings"].append(
                    {"file": str(p), "rule": rule, "match": m.group(0)[:24]})
        for m in HIGH_ENTROPY.finditer(text):
            if shannon(m.group(0)) >= 4.3:
                report["findings"].append(
                    {"file": str(p), "rule": "high_entropy", "match": m.group(0)[:12] + "..."})
    report["score"] = sum(WEIGHTS.get(f["rule"], 5) for f in report["findings"])
    return report

if __name__ == "__main__":
    rep = scan(staged_files())
    Path("preflight-report.json").write_text(json.dumps(rep, indent=2))
    print(f"{len(rep['files'])} files, {len(rep['findings'])} findings, score={rep['score']}")
    sys.exit(1 if rep["score"] >= 20 else 0)
```

Run it before any agent step reads the repository, and wire the exit code into whatever already builds your prompt:

```
git add -A
python preflight.py || { echo "egress blocked: redact or self-host this turn"; exit 1; }
```

That single `||` is the whole integration. If the gate fails, the agent does not get a prompt, and the failure is loud, cheap, and reproducible on a colleague's machine.

A score is only useful if it maps to an action, so write the mapping down and keep it short. Mine is three bands, and I would rather you copy the shape than the numbers.

After redaction, rebuild the prompt from the sanitised files rather than the working tree, because a placeholder that is regenerated from disk is a placeholder that quietly disappears. The report file matters too: it is the evidence you attach when a reviewer asks whether the agent ever saw production keys.

Now the comparison becomes concrete, because each row of your data classification points at a default path instead of a preference.

| Data class | Free hosted model | Free server option | Paid hosted | Self-hosted | 
|---|---|---|---|---|
| Public snippets | yes | yes | yes | yes | 
| Internal source | after redaction | verify where it runs and what it logs | after redaction | yes | 
| Operational data | narrow window only | verify | with agreement | yes | 
| Credentials | never | never | never | rotate first | 
| Regulated data | no | verify, likely no | only with contract | yes | 

Every cell marked "verify" is a question for the vendor's terms and logs page, not something I can answer for you from a blog post. Ask two things plainly: are prompts retained, and are prompts used for training? If the answer is vague, treat the cell as a no and move the workload.

Disclosure: This article was prepared as part of MonkeyCode's product outreach.

MonkeyCode offers free model access and a free server option, which makes it a practical sandbox for steps 3 and 4 above, because you can rehearse the gate against a real allowance instead of a hypothetical invoice. What it does not do is answer your data-retention questions for you; a free server changes who pays for compute, and it does not by itself change where logs live or how long they persist. Verify the current allowance and terms yourself before publishing numbers, since quotas and model lineups move faster than any article written about them.

If you want a low-stakes first run, point the script at a throwaway branch with a deliberately fake `AWS_SECRET` in it and watch the exit code flip. That is ten minutes of work and it tells you more about your workflow than another pricing table.

The gate is a heuristic, not a data-loss-prevention system: regexes miss custom secret formats, entropy checks flag minified bundles and base64 assets, and nothing here inspects what a provider does after the request lands. If you are in a regulated environment, pair this with real DLP tooling and a reviewed vendor agreement rather than replacing one with the other. If your repository already has committed credentials, rotate them first, because redaction of a live key is theatre.

Teams shipping purely public documentation can skip this entirely, and solo prototypes on public sample code will find the friction not worth the payoff. The gate earns its keep when private source, customer identifiers, or long-lived tokens routinely flow through an agent that someone else hosts.

When you next weigh free tokens against a self-hosted box, ask what actually left your machine during the last ten agent turns, and whether you could prove the answer. If you cannot, you are not comparing three options honestly; you are comparing three prices and guessing at the risk. Build the gate, get the exit code, and let the payload decide which columns of the table are even open to you.
