security
Air-gapped coding copilots: complete isolation for sensitive codebases
Air-gapped coding copilots run AI assistants entirely on-premises without external API calls, enabling code suggestions for classified or regulated environments.

Defense contractors, healthcare platforms, and financial institutions face a common problem: their engineers want AI coding assistants, but their compliance teams won't permit code or context to leave the building. Public cloud LLMs are a non-starter when your repository contains classified algorithms, patient data schemas, or proprietary trading logic. You need the productivity gains of a copilot without the exfiltration risk of a third-party API.
Air-gapped coding copilots run entirely inside your perimeter—no model weights, training data, or inference requests cross the network boundary. They require rethinking the entire stack: where models live, how they're updated, what guardrails prevent accidental leakage, and how you audit what the agent actually does. The goal isn't just compliance checkbox theater; it's building a system where your security team can trace every byte that moves and your engineers still get useful suggestions.
What air-gapped actually means for coding assistants
True air-gapping is stricter than "runs in your VPC." It means:
- Model weights stored on-premises. The LLM binary lives on servers you control, behind firewalls that drop outbound traffic. No calls to OpenAI, Anthropic, or Gemini APIs. If you need to update the model, you physically transfer files via approved media or a controlled one-way pipe.
- No telemetry phone-home. Standard SaaS copilots send usage analytics, error reports, and aggregated code patterns back to vendors. Air-gapped systems eliminate this entirely or route logs to local SIEM tools only.
- Inference happens locally. Every token generation, every embedding lookup, every tool call execution stays within the isolated network segment. The agent never sees public IP space.
In practice, you often see hybrid setups: a fully disconnected development cluster for classified work, with occasional batch transfers of anonymized logs for compliance review. The key is designing the system so the default path is zero egress.
Self-hosting the model layer
The first engineering decision is which model to run. Most teams pick a recent open-weights model—Llama 3.3, DeepSeek, Qwen, Mixtral—because you can download the weights once and redistribute them internally without licensing headaches. A 70B parameter model fits comfortably on a single 8×H100 node; smaller teams use quantized 8B or 34B variants on A100s or even CPU-only deployments if latency tolerance is high.
You'll run an inference server like vLLM, TensorRT-LLM, or llama.cpp behind an internal load balancer. The setup looks like:
# Example: vLLM on an internal cluster
vllm serve /mnt/models/llama-3.3-70b-instruct \
--host 0.0.0.0 \
--port 8000 \
--tensor-parallel-size 8 \
--max-model-len 32768
Your editor or agent framework hits this endpoint instead of an external API. You control rate limits, context window size, and which system prompts are allowed. If a compliance rule says "no code containing the string SSN- may be sent to the model," you enforce that in a middleware layer before inference.
The operational burden is real: you're now responsible for GPU uptime, CUDA driver patching, and model hot-swaps when you want to upgrade. Teams often dedicate a platform engineer to this full-time. The payoff is complete auditability—every request is a local log entry you can grep.
The agent loop under isolation constraints
Goatfied's core loop is plan → constrain → edit → validate → retry. In an air-gapped deployment, each stage stays internal:
1. Plan. The agent reads your repository state from a local file system or Git server. It generates a task breakdown using the internal LLM.
2. Constrain. Before making edits, the agent checks compile/lint/test requirements. These run in a sandboxed container—also local—so build artifacts never leave the perimeter.
3. Edit. The LLM proposes small, reversible diffs. The agent writes them to a working branch in your internal Git.
4. Validate. Run your CI pipeline (Jenkins, GitLab Runner, whatever you already have) in the same network segment. TypeScript compilation, pytest, cargo check—all local.
5. Retry. If validation fails, the agent reads the error logs (still local) and generates a fix.
The critical insight is that none of these steps inherently require internet access. The agent needs a model, a code execution environment, and a version control system. If all three are on-premises, the loop closes without crossing the boundary.
You do lose some conveniences. Public package registries (npm, PyPI, crates.io) aren't reachable by default. Most teams mirror approved dependencies to an internal Artifactory or Nexus instance. The first-time setup cost is high; the ongoing benefit is you know exactly which libraries are in play and can audit their provenance.
Preventing accidental exfiltration
Even with a local model, careless tool design can leak data. Common failure modes:
- An agent tool that runs
curlwithout a wrapper. If the LLM hallucinates a command likecurl https://pastebin.com/upload, it tries to send data out. The network firewall blocks it, but you've now logged an attempted violation. - Embeddings or RAG indices syncing to a cloud vector DB. Some copilot architectures store code embeddings in Pinecone or Weaviate. In an air-gapped setup, you run pgvector, Qdrant, or Milvus on-prem.
- LLM-generated file paths that reference external mounts. If the agent writes to
/mnt/exfil-bucket/, and that mount is accidentally a cloud storage gateway, you have a problem.
Goatfied addresses this by sandboxing tool calls in ephemeral containers with no network and a read-only root filesystem. The agent can invoke npm install, cargo build, or pytest, but those commands run inside a gVisor or Firecracker microVM that physically cannot egress. If the LLM tries to sneak in a wget, the syscall fails before DNS resolution.
Another layer: secret detection before execution. Before the agent runs any command, scan the proposed arguments for patterns like API keys, SSH private keys, or AWS credentials. If a match is found, reject the tool call and log it. This catches prompt injection attempts where an attacker tricks the LLM into echoing a secret. See Secret detection before an agent ever runs a tool for implementation patterns.
Audit trails and compliance evidence
Air-gapped deployments often exist because of regulatory mandates—ITAR, FedRAMP High, HIPAA with extra scrutiny, or internal policies for intellectual property. Your security officer will ask: "How do I prove the agent didn't exfiltrate anything?"
The answer is structured logging at every boundary:
- Model API logs. Every prompt and completion, timestamped, with the Git commit hash of the code being edited.
- Tool execution logs. Every
subprocess.run()invocation, including arguments and exit codes, stored in a tamper-evident ledger (some teams use append-only S3 buckets with object lock, but in air-gapped setups it's often a local write-ahead log with cryptographic checksums). - Network flow logs. Even though outbound traffic is blocked, log every denied connection attempt. If you see repeated
DENYentries to8.8.8.8:443, investigate why the agent is trying to reach Google DNS. - Diff and validation results. For each proposed code change, store the before/after diff and the CI pipeline output that validated it.
Goatfied surfaces this as a per-session audit view: you can reconstruct the entire reasoning chain from initial prompt to final merged commit. When an auditor asks, "Did the agent access patient records during this refactor?" you point to the logs showing it only read test fixtures and mock data.
Model updates without breaking isolation
One friction point: how do you get a newer model into the air gap without re-establishing internet connectivity? Options include:
- Physical media transfer. Download the model weights on an internet-connected workstation, copy to an encrypted USB drive approved for classified transfer, and hand-carry it to the air-gapped cluster. This is standard practice in defense and intelligence settings.
- One-way data diode. Some enterprises use hardware-enforced unidirectional network links. You push model files through the diode; data can flow in but never out.
- Batch sync during maintenance windows. If your air gap is policy-based rather than physically enforced, you might schedule a weekly window where outbound HTTPS is permitted to a single approved mirror, then re-seal the perimeter.
Each approach has tradeoffs. Physical media is slow but provably secure. Data diodes require capital expense. Policy-based windows are fast but increase attack surface during the sync.
The engineering task is designing a workflow where model updates are infrequent enough not to bottleneck development, but frequent enough that you're not stuck with a stale LLM for months. Most teams update quarterly unless a critical security patch lands.
When air-gapping is overkill (and when it's the only option)
Not every codebase needs this level of isolation. If you're building a SaaS app with no sensitive data and your compliance posture is "don't accidentally commit AWS keys," a public cloud copilot with good secret scanning is simpler and cheaper.
Air-gapped copilots make sense when:
- Legal or contractual obligations prohibit data egress. Defense primes working on classified contracts, healthcare companies under consent decrees, or banks with strict data residency rules.
- Intellectual property is the crown jewel. If your codebase contains novel algorithms worth billions in market cap, you may decide zero-trust isn't paranoid enough and go full isolation.
- You already operate air-gapped infrastructure. If you're running a SCIF or a classified network segment, adding a local LLM is marginal effort compared to the existing ops burden.
The honest tradeoff is reduced model quality and higher operational cost in exchange for complete control. You won't get the latest frontier model the day it releases, but you will sleep easier knowing your code never touched someone else's training pipeline.