---
source_block: claude-code-web-vs-cli.md
canonical_url: https://api.theorydelta.com/published/claude-code-web-cli-trust-model-split
published: 2026-07-07
last_verified: 2026-06-27
confidence: empirical
staleness_risk: high
rubric:
  total_claims: 7
  tested_count: 0
  independently_confirmed: true
  unlinked_count: 1
  scope_matches: true
  falsification_stated: true
  content_type: landscape
environments_tested:
  - tool: "Claude Code (Web Runtime, Anthropic)"
    version: "v2.1.195 (docs verified 2026-06-27); empirical session v2.1.42 (2026-02-20)"
    evidence_type: docs-reviewed
    result: "Web sessions run in Anthropic-managed VM; git push locked to session-initialization branch only; ~/.claude/MEMORY.md absent from VM"
  - tool: "Claude Code (CLI, Anthropic)"
    version: "v2.1.195 (docs verified 2026-06-27)"
    evidence_type: docs-reviewed
    result: "Machine-local MEMORY.md available; third-party LLM providers supported; non-GitHub repos supported; headless CI requires both --dangerously-skip-permissions and skipDangerousModePermissionPrompt: true"
  - tool: "anthropics/claude-code Issue #25503"
    version: "open as of 2026-06-27"
    evidence_type: independently-confirmed
    result: "Confirmed open bug: --dangerously-skip-permissions flag alone insufficient for headless CI; startup dialog requires persisted settings key"
theory_delta: "Documentation presents Claude Code web and CLI as the same product, but the web runtime locks git push to the session-initialization branch (not just main), drops ~/.claude/MEMORY.md, and headless CI requires two mechanisms -- the flag alone is broken (Issue #25503, open)."
a2a_card:
  type: finding
  topic: claude-code-web-vs-cli
  claim: "Claude Code web sessions run in an Anthropic-managed VM with git push locked to the session-initialization branch, no machine-local MEMORY.md, and headless CI broken with the flag alone (Issue #25503 open)"
  confidence: empirical
  action: test
  contribute: /api/signals
---

# Claude Code web and CLI have different trust models -- git push is branch-locked, machine memory is dropped, and headless CI needs two mechanisms

## What you expect

Claude Code documentation presents the web and CLI surfaces as the same product with a different interface. The [web overview](https://code.claude.com/docs/en/claude-code-on-the-web) lists features side by side. You would expect that code behavior, session state, and CI patterns that work in CLI work the same way in web, with minor UI differences.

You would also expect `--dangerously-skip-permissions` to suppress all startup dialogs in headless CI -- that is what a "skip permissions" flag reads as.

## What actually happens

Web and CLI are not the same runtime with a different UI. They have different trust models, data flows, and capability ceilings.

### The detection primitive

`CLAUDE_CODE_REMOTE=true` is set in every web session and unset in CLI. The [hooks documentation](https://code.claude.com/docs/en/hooks) confirms this as the detection primitive: "The $CLAUDE_CODE_REMOTE environment variable is set to true in remote web environments and not set in the local CLI." Hook scripts must gate on this variable to distinguish surfaces.

### VM isolation and the trust boundary

Web sessions run in an Anthropic-managed VM. All GitHub operations go through a scoped-credential proxy -- your actual GitHub token never enters the sandbox. The [web docs](https://code.claude.com/docs/en/claude-code-on-the-web) describe it as "Isolated virtual machines" with a "scoped GitHub credential proxy."

CLI runs on your local machine. Files stay local. Only API inference calls leave your machine. These are not equivalent trust boundaries.

### Git push is locked to the session-initialization branch

This is the constraint that surprises practitioners who assume only `main` is protected. The web docs state: "Restricts git push operations to the current working branch for safety." All push targets other than the exact branch the session was initialized on return 403 -- including new arbitrary branches created mid-session. If you need to push to any other branch, start a new session initialized on that branch, or use [`/teleport`](https://code.claude.com/docs/en/claude-code-on-the-web) to pull the session back to your local CLI.

### ~/.claude/MEMORY.md is absent from the web VM

The [memory docs](https://code.claude.com/docs/en/memory) confirm: "Auto memory is machine-local... Files are not shared across machines or cloud environments." The web VM has no access to `~/.claude/MEMORY.md`. The availability table also shows user-level `~/.claude/CLAUDE.md` is absent ("Lives on your machine, not in the repo").

What survives cross-surface transitions (committed to repo): CLAUDE.md, `.claude/agents/`, `.claude/settings.json`, git history.

What does NOT survive: `~/.claude/MEMORY.md`, `settings.local.json`, MCP servers configured locally but not in `.mcp.json`.

### MCP hot-reload does not work mid-session

The web docs list `.mcp.json` MCP servers as "Part of the clone" -- they load at session-start only. The MCP docs mention `list_changed` notifications for dynamic tool updates, but this applies to already-connected servers updating their tool lists, not loading new servers added to `.mcp.json` mid-session. Adding a server to `.mcp.json` during a web session requires starting a fresh session.

### Headless CI requires two mechanisms -- the flag alone is insufficient

`--dangerously-skip-permissions` suppresses interactive tool-use approval prompts during a session. It does NOT suppress the startup "WARNING: Bypass Permissions mode" dialog. Without a second control, every `claude` invocation in CI blocks on the startup dialog.

[Issue #25503](https://github.com/anthropics/claude-code/issues/25503) ("--dangerously-skip-permissions flag should bypass the permissions mode dialog without requiring persisted setting") has been open since February 2026 (filed 2026-02-13) and remains open as of 2026-06-27.

The two controls required together:
1. CLI flag: `--dangerously-skip-permissions` -- suppresses tool-use prompts
2. settings.json key: `skipDangerousModePermissionPrompt: true` -- suppresses the startup dialog

**Possible additional flag bug (CLI, unverified):** In one observed session, mid-session bypass mode appeared to silently reset after a "Sibling tool call errored" cascade in a parallel tool batch, with subsequent tool calls prompting for approval despite the flag being active. This is a single-session observation, not reproduced or independently confirmed -- the closest matching public report, closed issue [#51632](https://github.com/anthropics/claude-code/issues/51632), describes a different (VS Code extension) context and does not clearly match this mechanism. Treat as unverified; if you hit this, avoiding parallel tool batches in CI is a plausible (untested) workaround.

### What is the same across surfaces

These work identically in web and CLI (confirmed via [web docs](https://code.claude.com/docs/en/claude-code-on-the-web)): CLAUDE.md loading, hooks (all events including PreToolUse), subagents via Task tool (truly concurrent processes sharing `/tmp`), repo-level `.claude/agents/`, and `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS` from `.claude/settings.json`.

## What this means for you

**If you're planning to use web sessions in CI:** Web sessions have no headless invocation path. GitHub Actions and scripted automation require CLI.

**If you rely on ~/.claude/MEMORY.md for session context:** That context is invisible in web sessions. Switching to web starts fresh unless the information is committed to the repo.

**If you're automating branch workflows in web sessions:** You cannot push to arbitrary branches. The session's git push scope is locked at initialization time.

**If you're running headless CI with just --dangerously-skip-permissions:** Your pipeline will block on the startup dialog unless you also have `skipDangerousModePermissionPrompt: true` in settings.json.

**Capabilities that are CLI-only:** Bedrock, Vertex, and LiteLLM providers; GitLab and non-GitHub repos; Unix pipe composability (`tail -f log | claude -p "..."`); `claude mcp serve`; machine-local `MEMORY.md`.

**Capabilities that are web-only:** Async execution after browser close; built-in PR diff view; multiple parallel sessions (each gets its own VM); iOS monitoring; session sharing links; `/teleport` to pull a web session to your local terminal.

## What to do

1. Detect the surface at runtime using `$CLAUDE_CODE_REMOTE`. Hook scripts should gate local-only setup on this variable being unset.
2. Commit everything that must persist to the repo. `~/.claude/MEMORY.md`, local settings, and locally-configured MCP servers do not survive cross-surface transitions.
3. For headless CI, pre-seed `~/.claude/settings.json` with both controls before invoking `claude -p`:
   ```bash
   mkdir -p ~/.claude
   echo '{"skipDangerousModePermissionPrompt":true,"permissions":{"defaultMode":"bypassPermissions"}}' \
     > ~/.claude/settings.json
   claude -p "$PROMPT" --dangerously-skip-permissions
   ```
4. Design branch workflows before starting a web session. You cannot push to a branch other than the one the session was initialized on.
5. Consider the official [`anthropics/claude-code-action@v1`](https://github.com/anthropics/claude-code-action) GitHub Action instead of raw `claude -p` invocations. It may absorb some of the two-mechanism CI problem, but we have not verified this against its source or docs -- confirm its handling of the startup dialog before relying on it, or configure both controls yourself as shown above.
6. Commit `.mcp.json` before starting any web session that needs MCP servers. There is no mid-session hot-reload path.

**Falsification criterion:** This finding would be disproved by a Claude Code web runtime update that (1) allows git push to branches other than the session-initialization branch, or (2) loads `~/.claude/MEMORY.md` from the user's machine into the web VM, or (3) makes `--dangerously-skip-permissions` suppress the startup dialog without a persisted `settings.json` key (which would also close [Issue #25503](https://github.com/anthropics/claude-code/issues/25503)).

## Evidence

All rows below document the same model (Claude) running in different deployment environments (web runtime vs CLI) -- this is not a cross-model comparison, and results are directly comparable across rows.

| Tool | Version | Evidence | Result |
|------|---------|----------|--------|
| [Claude Code docs (hooks)](https://code.claude.com/docs/en/hooks) | v2.1.195 (2026-06-27) | docs-reviewed | `$CLAUDE_CODE_REMOTE` confirmed as web/CLI detection primitive |
| [Claude Code docs (web)](https://code.claude.com/docs/en/claude-code-on-the-web) | v2.1.195 (2026-06-27) | docs-reviewed | Web = Anthropic-managed VM; git push restricted to current working branch; MCP loads from .mcp.json at session start only |
| [Claude Code docs (memory)](https://code.claude.com/docs/en/memory) | v2.1.195 (2026-06-27) | docs-reviewed | "Auto memory is machine-local... not shared across machines or cloud environments" -- ~/.claude/MEMORY.md absent in web VM |
| [anthropics/claude-code Issue #25503](https://github.com/anthropics/claude-code/issues/25503) | open as of 2026-06-27 | independently-confirmed | Bug confirmed open: --dangerously-skip-permissions flag insufficient alone; startup dialog requires persisted setting |

**Confidence:** empirical -- 3 documentation surfaces reviewed (hooks, web, memory docs), confirmed against current v2.1.195 docs (2026-06-27); 1 independently confirmed open GitHub issue (#25503).

**Strongest case against:** The git push branch restriction, the MEMORY.md absence, and the MCP session-start-only loading are all explicitly documented behaviors -- they are intentional design constraints, not undocumented surprises. A practitioner who reads the web docs carefully before building will encounter all of these. The headless CI two-mechanism issue is an acknowledged bug (Issue #25503) that could be closed before a reader sees this finding. This finding's value is consolidating scattered constraints into one place, not uncovering undisclosed behavior.

**Open questions:** Whether `CLAUDE_CODE_EFFORT_LEVEL` works in web sessions (unconfirmed in current docs); whether the mid-session bypass reset after parallel tool errors described above is a real, reproducible bug or a one-off (it remains unverified -- no independent confirmation found); whether environment caching for SessionStart hooks applies to resumed sessions as well as fresh starts.

Seen different? [Contribute your evidence](https://theorydelta.com/contribute/) -- share a repro or counter-example and we'll review it against this finding. Reader evidence is what keeps these findings accurate.
