This section examines the extension and security architectures that differentiate production-grade coding agents from prototypes. We cover Claude Code's 8-event hook lifecycle, the Model Context Protocol (MCP) ecosystem with 3,000+ servers now governed by the Linux Foundation, OS-level sandboxing approaches ranging from Codex CLI's Seatbelt/Landlock to Warp's cloud sandboxes, and the approval workflow patterns that balance developer velocity with safety.
The key insight: extensibility and security are not trade-offs but complementary layers. The most competitive agents provide hooks for automation, MCP for tool integration, OS-level sandboxing for isolation, and configurable approval workflows for human oversight.
Claude Code provides the most comprehensive hook system in the coding agent market, enabling deterministic automation at 8 key lifecycle points. Hooks are external commands or prompts that execute at defined events, giving developers the ability to validate, enrich, block, or redirect agent behavior without modifying the agent itself.
The lifecycle covers the full span of a coding session, from initialization through prompt processing, tool execution, and termination. Each hook receives a JSON payload via stdin and can influence the agent through structured JSON output on stdout.
| Event | Fires When | Key Capabilities | Exit Code Behavior |
|---|---|---|---|
| SessionStart | Session initializes | Environment setup, inject system context, load configs | Non-zero: warning only |
| UserPromptSubmit | Before Claude processes a prompt | Validate, enrich, or block prompts; inject additionalContext via stdout | Exit 2: block prompt |
| PreToolUse | Before a tool executes | Approve, deny, or modify tool calls; matcher filters by tool name | Decision: allow/deny/ask |
| PostToolUse | After a tool returns | React to results, add feedback, audit logging | "block" to provide feedback |
| Stop | Agent decides to stop | Evaluate completion, force continuation if tasks remain | continue: true/false |
| SubagentStop | A dispatched subagent completes | Validate subagent output, aggregate results | continue: true/false |
| PreCompact | Before context window compaction | Preserve critical context, inject summaries | Non-zero: warning only |
| Notification | Agent emits a notification | Custom alerts, CI integration, Slack/email notifications | Async, non-blocking |
Hooks are configured in .claude/settings.json at the project or user level. Each event contains an array of hook groups, and each group can include a matcher (for tool-specific hooks) and an array of hooks to execute.
// .claude/settings.json
{
"hooks": {
"SessionStart": [{
"hooks": [{
"type": "command",
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/setup-env.sh"
}]
}],
"UserPromptSubmit": [{
"hooks": [{
"type": "command",
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/validate-prompt.sh"
}]
}],
"PreToolUse": [{
"matcher": "Write|Edit",
"hooks": [{
"type": "command",
"command": "node $CLAUDE_PROJECT_DIR/.claude/hooks/check-style.js"
}]
},
{
"matcher": "Bash",
"hooks": [{
"type": "command",
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/validate-command.sh"
}]
}],
"PostToolUse": [{
"matcher": "Bash",
"hooks": [{
"type": "command",
"command": "echo '{\"tool\": \"'$TOOL_NAME'\", \"ts\": \"'$(date -u)'\"}' >> ~/.claude/audit.log"
}]
}],
"Stop": [{
"hooks": [{
"type": "prompt",
"prompt": "Evaluate if all tasks are complete. Check todo list status. If tasks remain, set continue: true."
}]
}],
"PreCompact": [{
"hooks": [{
"type": "command",
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/save-critical-context.sh"
}]
}],
"Notification": [{
"hooks": [{
"type": "command",
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/notify-slack.sh"
}]
}]
}
}
Hooks communicate back to Claude Code via structured JSON on stdout. The schema varies by event type, but the core fields are consistent: hookSpecificOutput for event-specific data, systemMessage for injecting context, and continue for flow control.
// PreToolUse hook response - APPROVE with modification
{
"hookSpecificOutput": {
"permissionDecision": "allow",
"updatedInput": {
"file_path": "/src/components/Button.tsx",
"content": "// Auto-formatted by hook\nimport React from 'react';\n..."
}
},
"systemMessage": "Path corrected to match project structure. Content auto-formatted.",
"continue": true
}
// PreToolUse hook response - DENY with explanation
{
"hookSpecificOutput": {
"permissionDecision": "deny",
"reason": "Cannot write to /etc directory. Use project-local configs instead."
},
"systemMessage": "Write blocked by security policy. Suggest alternative path.",
"continue": true
}
// PostToolUse hook response - BLOCK with feedback
{
"decision": "block",
"reason": "ESLint errors detected in output",
"hookSpecificOutput": {
"additionalContext": "Fix: Remove unused import on line 5, add missing semicolon on line 12"
}
}
// UserPromptSubmit hook response - ENRICH with context
{
"hookSpecificOutput": {
"additionalContext": "Current sprint: AUTH-2024. Branch: feature/oauth-flow. Test suite: 94% passing."
},
"continue": true
}
The hook system transforms Claude Code from a developer tool into an enterprise-governable platform. Organizations can enforce coding standards (PreToolUse), maintain audit trails (PostToolUse), prevent context loss during long sessions (PreCompact), and integrate with existing CI/CD pipelines (Notification) -- all without forking the agent. No other coding agent provides this level of lifecycle control.
The Model Context Protocol (MCP) has become the universal standard for tool integration in AI coding agents. Originally developed by Anthropic, MCP is now governed by the Linux Foundation's Agentic AI Foundation (AAIF), with an ecosystem of 3,000+ servers providing access to external services, APIs, and data sources.
MCP servers are configured per-project or globally. The configuration specifies the server command, arguments, and environment variables. Servers are launched as child processes using stdio transport by default.
// ~/.claude.json (global) or .mcp.json (project-level)
{
"mcpServers": {
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": {
"GITHUB_TOKEN": "${GITHUB_TOKEN}"
}
},
"playwright": {
"command": "npx",
"args": ["@playwright/mcp@latest"]
},
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/allowed/path"]
},
"slack": {
"command": "npx",
"args": ["-y", "@anthropic/mcp-server-slack"],
"env": {
"SLACK_BOT_TOKEN": "${SLACK_BOT_TOKEN}"
}
},
"memory": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-memory"]
}
}
}
// Goose: MCP-first configuration (extensions.yaml)
extensions:
github:
type: builtin
name: github
env:
GITHUB_TOKEN: "${GITHUB_TOKEN}"
jira:
type: mcp
command: npx
args: ["-y", "@anthropic/mcp-server-jira"]
env:
JIRA_URL: "${JIRA_URL}"
JIRA_TOKEN: "${JIRA_TOKEN}"
custom_api:
type: mcp
url: "http://localhost:3001/sse" # Remote SSE transport
Each MCP server adds its tool definitions to the context window. A single server can consume 2,000-10,000 tokens for tool schemas alone. With 10+ servers active, usable context can shrink from 200k to ~70k tokens. Mitigation strategies:
disabledMcpServers to selectively disable unused servers per project/context command in Claude Code.mcp.json to scope servers to projects that need themThe MCP ecosystem has grown rapidly since its open-source release. With governance now under the Linux Foundation's AAIF, the protocol has achieved broad adoption across all major coding agents and a growing catalogue of community and vendor-maintained servers.
| MCP Server | Provider | Key Tools Exposed | Token Overhead | Use Case |
|---|---|---|---|---|
| GitHub | Anthropic / Official | search_repos, create_issue, create_pr, get_file_contents, list_commits | ~3,500 tokens | Repository management, code review, issue tracking |
| Playwright | Microsoft / Official | navigate, click, fill, screenshot, evaluate | ~4,200 tokens | Browser automation, E2E testing, web scraping |
| Slack | Anthropic / Official | send_message, list_channels, search_messages, upload_file | ~2,800 tokens | Team notifications, deployment alerts, status updates |
| Filesystem | Anthropic / Official | read_file, write_file, list_directory, search_files, move_file | ~2,200 tokens | Sandboxed file access beyond agent's native tools |
| Jira | Anthropic / Official | create_issue, search_issues, update_issue, get_project, add_comment | ~3,100 tokens | Sprint management, ticket creation, project tracking |
| Linear | Community | create_issue, list_issues, update_status, get_project, search | ~2,600 tokens | Issue tracking, sprint planning, workflow automation |
| PostgreSQL | Community | query, list_tables, describe_table, execute | ~1,800 tokens | Database exploration, data analysis, migrations |
| Memory | Anthropic / Official | store, retrieve, search, delete | ~1,500 tokens | Persistent key-value memory across sessions |
| Agent | MCP Support | Transport | Config Location | Notes |
|---|---|---|---|---|
| Claude Code | Full | stdio, SSE | .mcp.json, ~/.claude.json |
Native MCP client; project + global config |
| Codex CLI | Full | stdio | codex.json |
Launched via sandbox; respects network policy |
| Cline | Full | stdio, SSE | VS Code settings / .mcp.json |
MCP marketplace in VS Code extension |
| Goose | Full (MCP-first) | stdio, SSE | extensions.yaml |
Architecture built around MCP; 3,000+ extensions |
| Qwen Code | Full | stdio | .mcp.json |
Forked from Gemini CLI; inherited MCP support |
| OpenCode | Full | stdio, SSE | opencode.json |
Go-based MCP client implementation |
| Aider | Full | stdio | .aider.mcp.json |
Added in 2025; complements repo-map tools |
| Droid | Full | stdio | CLI config | Selectively exposes MCP tools to reduce token overhead |
| Warp | Full | stdio (sandboxed) | Agent config | MCP servers run inside cloud sandbox |
| OpenManus | Full | stdio, SSE | Framework config | MCP integrated into tool orchestration layer |
| Letta Code | Full | stdio | Letta server config | MCP tools alongside persistent memory tools |
| Vibe CLI | Full | stdio | .mcp.json |
Mistral's agent supports standard MCP config |
| Replit Agent | Partial | Internal | Platform-managed | Cloud-hosted; MCP servers managed by platform |
As of January 2026, every major coding agent supports MCP. This represents a remarkable convergence: the protocol went from Anthropic-specific to Linux Foundation-governed industry standard in under 18 months. The practical implication is that tool integrations (GitHub, Jira, databases, browsers) are now write-once, run-anywhere across agents. Goose's MCP-first architecture, where the entire extension system is built on MCP, represents the most committed adoption.
Sandboxing is the most architecturally divergent area across coding agents. Approaches range from OS-kernel enforcement (Codex CLI) to cloud isolation (Warp) to real-time static analysis (Droid) to permission-based workflows (Claude Code, Cline). The right choice depends on the threat model: protecting from accidental damage vs. defending against prompt injection vs. meeting compliance requirements.
| Agent | macOS | Linux | Windows | Network Control |
|---|---|---|---|---|
| Codex CLI | Seatbelt (sandbox-exec) | Landlock + seccomp | Restricted tokens / WSL | Disabled by default |
| Claude Code | Permission workflow | Permission workflow | Permission workflow | Enabled |
| Cline | Human-in-loop approval | Human-in-loop approval | Human-in-loop approval | Enabled |
| Goose | Local execution trust | Local execution trust | Local execution trust | Enabled |
| Warp | Cloud sandbox (Namespace) -- host OS irrelevant | Isolated by default | ||
| Droid | DroidShield real-time static analysis | Configurable | ||
| Qwen Code | Docker sandbox (--sandbox flag) |
Container-isolated | ||
| Replit Agent | Cloud sandbox with checkpoints | Isolated by default | ||
Codex CLI implements the most comprehensive OS-native sandboxing, using platform-specific kernel features to restrict file system access and network connectivity at the operating system level.
;; Seatbelt Profile - Scheme-like syntax ;; Applied via sandbox-exec before spawning the agent shell (version 1) (deny default) ;; Deny everything by default ;; Allow reading system libraries and tools (allow file-read* (subpath "/usr")) (allow file-read* (subpath "/System")) (allow file-read* (subpath "/Library")) (allow file-read* (subpath "/private/var/tmp")) ;; Allow read/write only in workspace directory (allow file-read* file-write* (subpath "/workspace")) ;; Allow process execution (needed for build tools) (allow process-exec* (subpath "/usr/bin")) (allow process-exec* (subpath "/workspace/node_modules/.bin")) ;; CRITICAL: Network disabled by default (deny network*) ;; Allow specific network if --full-auto enables it ;; (deny network-outbound (remote tcp "*:*"))
// Rust implementation from Codex CLI source
pub fn apply_sandbox_policy_to_current_thread(
policy: &SandboxPolicy,
cwd: &Path
) -> Result<()> {
// Step 1: Create Landlock ruleset for filesystem access
let ruleset = Ruleset::new()
.handle_access(AccessFs::Execute)?
.handle_access(AccessFs::WriteFile)?
.handle_access(AccessFs::ReadFile)?
.handle_access(AccessFs::ReadDir)?;
// Step 2: Add read-only paths
for path in &policy.readable_roots {
ruleset.add_rule(PathBeneath::new(
path,
AccessFs::ReadFile | AccessFs::ReadDir | AccessFs::Execute
))?;
}
// Step 3: Add writable paths (workspace only)
for path in &policy.writable_roots {
ruleset.add_rule(PathBeneath::new(
path,
AccessFs::ReadFile | AccessFs::ReadDir |
AccessFs::WriteFile | AccessFs::Execute
))?;
}
// Step 4: Block network via seccomp if policy requires
if !policy.network_access {
apply_seccomp_network_filter()?;
// Uses seccomp BPF to block socket(), connect(), bind()
// syscalls, preventing all network I/O
}
// Step 5: Enforce -- irreversible after this point
ruleset.restrict_self()?;
Ok(())
}
fn apply_seccomp_network_filter() -> Result<()> {
// BPF filter blocks: socket(), connect(), bind(), listen(), accept()
let filter = SeccompFilter::new(vec![
SeccompRule::new(libc::SYS_socket, SeccompAction::Errno(libc::EPERM)),
SeccompRule::new(libc::SYS_connect, SeccompAction::Errno(libc::EPERM)),
SeccompRule::new(libc::SYS_bind, SeccompAction::Errno(libc::EPERM)),
])?;
filter.apply()?;
Ok(())
}
Codex CLI's sandboxing is irreversible after application. Once restrict_self() is called, even root cannot lift the restrictions for that process. This is fundamentally stronger than permission-based workflows where a sufficiently persuasive prompt injection could convince an agent to bypass its own rules. The trade-off: agents cannot install packages or access APIs that require network unless explicitly enabled with --full-auto mode.
Beyond Codex CLI's OS-native approach, several agents have developed novel sandboxing strategies tailored to their deployment models. These range from cloud-native isolation to AI-powered static analysis.
Warp takes a fundamentally different approach by running agent tasks in ephemeral cloud sandboxes provided by Namespace, eliminating the need for local OS sandboxing entirely.
node_modules, pip, cargo) are shared across sandboxes to avoid redundant downloads, reducing cold-start from minutes to seconds.Factory.ai's Droid takes a unique AI-powered approach to security: rather than sandboxing execution, DroidShield performs real-time static analysis on every code change before it is applied, catching unsafe patterns before they execute.
| Property | Detail |
|---|---|
| Approach | AI-powered real-time static analysis of generated code |
| Timing | Pre-execution: analyzes code before it runs, not after |
| Coverage | Detects unsafe system calls, data exfiltration, credential exposure, supply chain attacks |
| Certifications | ISO 42001 SOC 2 ISO 27001 GDPR CCPA |
| Advantage | Does not restrict legitimate operations (no sandbox overhead); catches semantic threats that sandboxing cannot |
| Limitation | Static analysis can have false positives; cannot prevent runtime exploits in existing code |
Qwen Code provides an opt-in Docker sandbox activated via the --sandbox CLI flag. This runs the agent's shell commands inside a qwen-code-sandbox container image, providing filesystem and network isolation through standard container boundaries.
# Launch Qwen Code with Docker sandbox $ qwen-code --sandbox # Under the hood: # 1. Pulls/builds qwen-code-sandbox image # 2. Mounts workspace as /workspace (rw) # 3. All Bash tool calls execute inside container # 4. Network access controlled by Docker network policy # Docker sandbox configuration docker run --rm \ -v "$(pwd):/workspace" \ -w /workspace \ --network=none \ # Network disabled by default --memory=4g \ # Memory limit --cpus=2 \ # CPU limit qwen-code-sandbox \ /bin/bash -c "$COMMAND"
Replit Agent runs entirely in Replit's cloud environment, providing sandbox isolation by default. Its unique contribution is the checkpoint system that captures snapshots of the entire environment state, enabling rollback to any previous point.
The five approaches represent a spectrum of trust models:
For agents that do not use OS-level sandboxing, the approval workflow is the primary safety mechanism. These range from per-action human approval (Cline) to configurable permission rules (Claude Code) to full bypass ("YOLO") modes for trusted environments.
Cline implements a shadow git repository that runs alongside the user's actual git repo, creating a checkpoint after every tool call. This enables granular rollback without affecting the user's commit history.
// VS Code settings.json (Cline extension)
{
"cline.autoApprove": {
"readOperations": true, // File reads: auto-approved
"writeOperations": false, // File writes: require human approval
"terminalCommands": false, // Shell commands: require approval
"browserActions": false, // Web automation: require approval
"mcpTools": false // MCP server tools: require approval
},
"cline.yoloMode": false // Bypass ALL approvals (dangerous)
}
// YOLO Mode - bypasses all approval checks
// WARNING: Only use in disposable environments (containers, VMs)
{
"cline.yoloMode": true,
"cline.yoloModeAllowList": [
"npm test",
"npm run build",
"git status",
"git diff"
]
// Commands not in allowList still blocked even in YOLO mode
}
// .claude/settings.json
{
"permissions": {
"allow": [
"Read(*)", // All file reads: auto-approved
"Bash(git:*)", // All git commands: auto-approved
"Bash(npm:test)", // npm test: auto-approved
"Bash(npm:run build)", // npm build: auto-approved
"Bash(npx:prettier *)", // Prettier formatting: auto-approved
"Write(.claude/*)", // Writing to .claude dir: auto-approved
"mcp__github__get_*" // GitHub read operations: auto-approved
],
"deny": [
"Bash(rm -rf *)", // Destructive commands: always blocked
"Write(/etc/*)", // System files: always blocked
"Bash(curl *)", // Network commands: blocked
"Bash(wget *)", // Network commands: blocked
"Bash(sudo *)", // Privilege escalation: blocked
"Bash(chmod 777 *)" // Dangerous permissions: blocked
]
}
}
// Pattern matching supports:
// - Wildcards: * matches any sequence
// - Tool prefixes: Read, Write, Bash, Edit, mcp__*
// - Nested patterns: Bash(git:push origin *)
Permission-based approval workflows are advisory, not enforceable. A sophisticated prompt injection could potentially convince the agent to reinterpret or circumvent permission rules. For high-security environments, combine approval workflows with OS-level sandboxing (Codex CLI pattern) or cloud isolation (Warp pattern). The defense-in-depth approach uses hooks (PreToolUse) + permissions + sandboxing together.
The following matrix compares the security posture of all 13 analyzed coding agents across four dimensions: sandbox type, network control, approval model, and compliance certifications.
| Agent | Sandbox Type | Network Control | Approval Model | Certifications |
|---|---|---|---|---|
| Aider | None (local trust) | Unrestricted | CLI confirmation prompts | -- |
| Claude Code | Permission workflow + hooks | Unrestricted (configurable via hooks) | Allow/deny rules, PreToolUse hooks, 3 permission tiers | SOC 2 (Anthropic) |
| Cline | Shadow git checkpoints | Unrestricted | Human-in-loop per action, auto-approve config, YOLO mode | -- |
| Codex CLI | OS-native (Seatbelt / Landlock / seccomp) | Blocked by default (kernel-enforced) | 3 modes: suggest / auto-edit / full-auto | SOC 2 (OpenAI) |
| Droid | DroidShield (real-time static analysis) | Configurable | AI-verified before execution | ISO 42001 SOC 2 ISO 27001 GDPR CCPA |
| Goose | Local execution trust | Unrestricted | Approval prompts for sensitive operations | -- |
| Letta Code | None (Letta server isolation) | Unrestricted | Server-side tool approval | -- |
| OpenCode | None (local trust) | Unrestricted | CLI confirmation prompts | -- |
| OpenManus | None (framework trust) | Unrestricted | Planning approval, tool-level hooks | -- |
| Qwen Code | Docker (opt-in via --sandbox) |
Container-isolated (when sandboxed) | CLI confirmation, auto-approve for reads | -- |
| Replit Agent | Cloud sandbox + checkpoints | Isolated by default | Platform-managed, checkpoint rollback | SOC 2 (Replit) |
| Vibe CLI | None (local trust) | Unrestricted | CLI confirmation prompts | -- |
| Warp | Cloud sandbox (Namespace) | Isolated by default (allowlist configurable) | Sandbox-enforced, short-lived credentials | SOC 2 |
Based on this analysis, coding agents fall into three security maturity tiers:
The extension and security landscape reveals three architectural imperatives for competitive coding agents:
Hook Systems: Claude Code Hooks Documentation
MCP Protocol: Model Context Protocol Specification, Linux Foundation AAIF
Sandboxing: Codex CLI (sandbox implementation), Namespace (Warp cloud sandbox), DroidShield (Factory.ai)
Agents: Cline, Qwen Code, Replit Agent, Warp, Goose
Part 2 of 6 · Coding Agent Engineering Analysis · January 2026