AI Coding Agents: Containment-First vs. Analyze-First Architecture

    Once an LLM can read and write files, run commands, and access the network, the central architectural question for an AI coding agent is where to put the constraint. This article compares the two root answers — containment-first (trust the kernel, push enforcement into the execution environment) and analyze-first (trust a semantic review layer plus tiered permissions) — covering their mechanisms, trust models, permission tiers, attack surfaces, and costs, followed by a head-to-head comparison and a layered defense-in-depth reference architecture with sample sandbox policy and tool declarations. It also gives measurable criteria, a minimal red-team test set, and common anti-patterns for choosing and validating your own design.

    1. Where the Divide Comes From: One Question, Two Answers

    Once a model stops merely “generating code” and can directly read and write files, execute commands, and reach the network, the engineering question reduces to a single one:

    When an action a model emits may cross a boundary, which layer should the constraint live in?

    The industry offers two fundamentally different answers. They are not a matter of “strong vs. weak” but of where the trust root sits:

    • Containment first: Assume model output is never trustworthy and push the constraint down into the execution environment. Make dangerous actions physically impossible to complete, rather than deciding whether they ought to be allowed.
    • Analyze first: Assume the constraint can live at the semantic layer. Use a reviewing model plus tiered permission policies to decide whether a given operation belongs to the current task and stays within bounds, escalating to a human when necessary.

    The choice matters because it sits at an architectural fork. Once made, it simultaneously locks in seven or eight design decisions that otherwise look independent: how many tools to expose, how to allocate the context budget, how to report a rejection, how many cross-platform implementations to write, and at what granularity audit logs are recorded. Treating it as “just picking a sandbox” typically costs you a round of rework later.


    2. Containment First: Putting the Trust Root in the Kernel

    2.1 The mechanism spectrum

    The containment route builds on isolation capabilities the operating system already provides. Roughly ordered by strength, there are four layers:

    1. System call filtering. Use the kernel’s call-filtering interface to establish an allowlist and block high-privilege calls (process tracing, mounting, kernel module loading, raw sockets, and so on). This narrows the capability surface, not the file surface.
    2. Kernel-level path access control. Describe the reachable scope declaratively — for example, “allow reads from the repo root, allow writes to the workspace scratch directory, deny everything else.” The critical difference is that the decision happens when the kernel opens a file, not when user space prefix-matches a command string. That is why symlink tricks, relative-path traversal, and /proc side channels are semantically impossible rather than merely filtered.
    3. Namespaces and control groups. Isolate the filesystem view, process view, network view, and user identity view, and use cgroups to cap CPU, memory, process count, and open file count. This layer addresses blast radius: even if the boundary is breached, resource consumption and visibility stay contained.
    4. Lightweight virtualization. Provide a hardware-level boundary for untrusted code or third-party dependency install scripts. Highest overhead, but also the highest bar to escape.

    A pragmatic implementation order is: capability trimming → path access control → namespace isolation → resource quotas, with network egress governed separately (see 2.5).

    2.2 Trust model

    The containment route’s trust assumption is very clean: trust the kernel, not the model.

    Before executing a command, the system does not need to understand what the command intends to do. It answers only one question — “are the resources it will touch inside the allowed set?” If not, deny. The decision logic is decoupled from semantics, so no amount of “persuading the model” can change the outcome.

    2.3 Permission tiers

    In practice these converge on three tiers, with explicit escalation as the only channel:

    Tier Filesystem Network Processes
    Read-only Whole repo readable, not writable Deny by default, allowlisted domains only Restricted
    Workspace-writable Repo writable, read-only outside the repo Egress proxy + domain allowlist Restricted
    Fully open Unrestricted Unrestricted Unrestricted

    The third tier should be treated as a “debug mode”: it requires explicit human confirmation, is time-boxed, and is fully audited. It should never be a default.

    2.4 Advantages

    • Deterministic blocking. The decision is kernel-level and enumerable; “the model misjudged” is not a failure mode.
    • Physical immunity to novel attacks. No matter how an attacker phrases or obfuscates the input, out-of-bounds system calls and file access simply do not go through.
    • Policy can be formally audited. The rule set is a finite data structure — it can be reviewed, unit-tested, and regression-tested.
    • Negligible overhead. Each system call decision is a microsecond-scale constant cost and consumes no model tokens.

    2.5 Costs and weak points

    • Silent failure. The feedback a model receives is often just “operation denied,” with no reason. It then keeps rewriting and probing, burning context and turns for nothing. You must design an explicit “denial explains itself” mechanism that returns the specific rule that was hit.
    • Coarse granularity. A fence can express “can this path be written,” but struggles with semantic-level constraints such as “this push targets the main branch directly” or “this command rewrites history.”
    • Real cross-platform engineering cost. Sandbox interfaces across operating systems are not equivalent in semantics or capability. Unified behavior means taking the intersection of capabilities; otherwise the same policy has different strength on different platforms, which creates a false sense of security.
    • Network egress is the hardest part. As long as an HTTP request can be issued, source code and credentials can be exfiltrated. File fences alone cannot prevent that; you must layer in an egress proxy, domain allowlist, and request-body auditing.
    • Dependence on kernel version. The escape surface evolves with the kernel and requires continuous tracking of the patch baseline.

    3. Analyze First: Putting the Trust Root in Semantic Judgment

    3.1 Three layers

    The analyze route is not “just one classifier.” Mature implementations typically have three layers:

    1. Intent classification layer. Decide what class of action this is (read, search, write, execute, network, delete), how risky it is, and whether it is consistent with the current task goal.
    2. Policy engine layer. Validate the structured parameters: path allow/deny lists, command-class matching, parameter value constraints, protected target branches, and so on. This layer must validate parsed parameters, not the raw command-line string.
    3. Interactive approval layer. For high-risk actions, surface an explanation and options: what is about to be executed, which files it affects, and whether it can be rolled back.

    3.2 Tooling design

    The analyze route almost inevitably moves toward a “professional toolbox”: capabilities are decomposed into a relatively large set of tools with explicit inputs and outputs (search, read, precise locate-and-replace, execute, web fetch, sub-task dispatch, language services, and so on), each carrying a structured input schema and returning structured results.

    The benefit is that policy can attach at the tool boundary: whether a tool is available at all, which parameters need approval, and how results are redacted can all be configured per tool. The cost is that the schemas themselves consume context budget.

    3.3 Advantages

    • Semantic judgment. It can distinguish “clear the build cache” from “delete the repository,” and recognize “the target of this push is a protected branch.”
    • Explainable interaction. On refusal it gives the reason and a viable alternative, so a human can decide quickly instead of staring at an error code.
    • Strong observability. Structured logs naturally record which tool was called, with what parameters, and what the result summary was — which makes auditing, replay, and quality attribution easy.
    • Cross-platform consistency. Policy lives in the application layer, so one implementation covers every host system.
    • Fine-grained permissions. You can allow edits to the test directory, require approval for source changes, and hard-deny CI configuration changes.

    3.4 Three real attack surfaces

    This route hands the trust root to a model, which makes the attack surface clearly enumerable:

    1. Prompt injection. Instructions planted in repository comments, docs, issue descriptions, or dependency package descriptions can steer the model into producing a command that “looks ordinary.” The attacker does not need to breach the system — only to change the model’s judgment.
    2. Command obfuscation. Encode then decode and execute; variable concatenation and indirect expansion; download-and-run; script wrapping script; logic hidden inside an interpreter’s -c string. The goal is to defeat pattern-based matching.
    3. Out-of-distribution inputs. Combinations the classifier has never seen, where confidence is inherently unreliable — and exactly the kind of input an attacker will deliberately construct.

    3.5 Secondary risks

    • Approval fatigue. Too many approvals train people to click through reflexively, and interactive approval degrades into decoration.
    • Trust root shift. Once the classifier becomes the only gate, its prompt, model version, and thresholds become the new attack target and the new source of change risk.
    • Latency and cost. Each decision may add a model call, raising end-to-end latency and token cost.

    4. Six-Dimension Comparison

    Dimension Containment first Analyze first
    Core mechanism Kernel-level capability trimming and path access control Intent classification + policy engine + interactive approval
    Platform implementation Separate implementation per host OS; behavior must be the intersection One application-layer implementation for all hosts
    Resistance to blocking High (deterministic) Depends on judgment being correct; bypass space exists
    Novel attacks Blocked by capability limits Possibly bypassed (out of distribution)
    Failure experience Prone to silent failure; needs explanation feedback Explainable and interactive
    Observability Weak (execution is a black box) Strong (structured tool calls are auditable)
    Permission granularity Coarse (resource + operation) Fine (per tool, per parameter)
    Additional overhead System-call level, near zero One model call per decision
    Main weak point Network egress, cross-platform consistency Injection, obfuscation, out-of-distribution inputs, approval fatigue

    The knock-on effect on tool shape is equally worth noting. A minimal toolset (one general execution entry point plus one atomic patch interface) has low context overhead and high flexibility, but its reliability depends on what the host environment preinstalls, its observability is weak, and its permission granularity is coarse. A rich toolset brings its own dependencies, structured results, and controllable permissions, but its schemas crowd the context window and it costs more to implement and maintain. The security model and the tool model are two sides of the same decision and cannot be chosen separately.


    5. Recommended Architecture: Layered Fusion with Defense in Depth

    In production, the real answer is usually not either/or but “analysis layer in front, isolation layer as the backstop.” The layers:

    • L1 Planning layer. Decompose the task into a plan first. The reconnaissance phase is read-only by default, and the plan is submitted for a single human approval instead of interrupting a human at every step.
    • L2 Semantic layer. Intent classification plus structured policy validation, responsible for “not bothering the human” — the vast majority of normal operations pass silently.
    • L3 Execution layer. All execution funnels into a single sandboxed process, with deterministic blocking enforced by the kernel, responsible for “even if it goes wrong, nothing bad happens.”
    • L4 Change layer. Code changes land in an isolated workspace and a temporary branch, with a snapshot taken before operations. Build artifacts go to temporary storage; long-lived data goes to object storage.
    • L5 Audit layer. Structured session logs plus full replay, with anomalous patterns wired into monitoring and alerting, supporting post-hoc attribution and rule regression.

    A few non-negotiable principles:

    • Least privilege by default. Any escalation is explicit, time-boxed, and audited.
    • Credentials never enter the sandbox. Only short-lived tokens are placed inside, exchanged through a controlled interface and invalidated after use.
    • Network egress must be governed separately. Deny by default, allowlist for exceptions, and record destination domains and request volume.
    • Dangerous actions are hard-blocked, not sent to approval. History rewrites, forced remote pushes, and production configuration changes should be refused outright rather than “asking a human.”

    Illustrative policy configuration:

    1. sandbox:
    2. fs:
    3. read: ["repo_root", "/usr/share/zoneinfo"]
    4. write: ["repo_root/**", "scratch_dir"]
    5. deny: ["**/.git/hooks/**", "**/.env*", "credential_paths"]
    6. exec:
    7. allow_syscalls: baseline # block tracing, mounting, kernel module loading, etc.
    8. deny_commands: ["force_push", "history_rewrite", "remote_shell_reverse"]
    9. net:
    10. default: deny
    11. allow_domains: ["package_registry", "internal_api"]
    12. resources:
    13. cpu: "2", memory: "4Gi", pids: 256, wall_clock: "15m"
    14. approval:
    15. auto_approve: [read, search, lint, unit_test]
    16. require_confirm: [write_source, install_dependency, run_script_from_repo]
    17. hard_deny: [push_main, deploy, secret_access]

    The corresponding tool declaration should also state its permission expectations explicitly, rather than leaving the model to guess from natural language:

    1. {
    2. "name": "run_tests",
    3. "input": { "suite": "string?", "filter": "string?" },
    4. "side_effects": ["exec", "read", "write:scratch_dir"],
    5. "requires": "auto_approve",
    6. "timeout_sec": 600
    7. }

    6. How to Tell Which Route Fits You

    6.1 Measurable criteria

    Do not choose based on a “feels safer” impression. Fix a set of metrics and compare against them:

    • Task completion rate (capability only, ignoring safety)
    • Escape rate: the share of red-team cases in which the boundary is successfully crossed
    • False-block rate: the proportion of normal operations wrongly denied (which directly drives wasteful model probing)
    • Human approvals per task: the hard metric for interaction cost
    • End-to-end p95 latency and token cost per task
    • Mean time to recovery: how long it takes to locate and roll back an incident from the audit log

    6.2 A minimal red-team case set

    Cover at least: obfuscated encoded commands, execution via variable concatenation, injection through in-repo docs and comments, dependency install script hooks, symlinks and path traversal, writes to temp files outside the workspace, network exfiltration attempts, pushes to protected branches, and reads of credential files. This set should be wired into CI as a regression suite and re-run on every rule or model change.

    6.3 Common anti-patterns

    • Doing only command-line string blocklist matching.
    • Treating a classifier score as the sole gate.
    • Having a file fence but no network egress control.
    • Mounting host credential directories into the sandbox.
    • Approval dialogs that dump the raw command, leaving the human with no basis to judge.
    • No structured audit trail and no replay, making post-hoc attribution impossible.

    7. Conclusion

    The split between containment first and analyze first is fundamentally a trade-off between “trading certainty for semantic blind spots” and “trading semantic understanding for certainty.” The former puts the trust root in the kernel: blocking is enumerable and immune to novel attacks, but it cannot see semantics, costs more across platforms, and struggles with network egress. The latter puts the trust root in semantic judgment: strong comprehension, explainability, and auditability, but it must face injection, obfuscation, and out-of-distribution inputs head-on, and it introduces latency and approval fatigue.

    The decision criteria are actually clear: whether the code source is trustworthy, whether the process runs unattended, and whether there are strict compliance and audit requirements. Untrusted sources, automated pipelines, and heavily regulated settings need containment first as the foundation; interactive development that must ship across platforms with fine-grained authorization benefits noticeably from the analyze-first experience. But most deployed systems converge on the same end state — a semantic layer that reduces interruptions to the human, an isolation layer that keeps the worst case under control, and an audit layer that leaves evidence behind for every boundary-crossing attempt.