Reference

Reference — How Six AI Coding Harnesses Assemble Context

What is in the model's context window at the start of a turn, where each piece comes from, and what silently fails. Claude Code, Claude Desktop, Cursor, opencode, Codex CLI, Gemini CLI.

This page is the ground truth behind every module prompt that says "find the always-on instruction file this harness loads every session." It answers that for six harnesses, with real paths.

Researched 2026-08-30 against primary sources. Every claim is marked CONFIRMED with the page or source file it came from, or UNCONFIRMED. Where a doc contradicts the shipped source, the source wins and the contradiction is recorded — four such cases appear below, and they are the most valuable rows on the page.

Read the marks. A gap named is more useful than a plausible guess, because this file is used to write commands that must actually work.

Before you trust any of it: three doc trees moved in 2026

Older guides point at URLs that now 404 or redirect. If your agent fetches those, it gets nothing and says so, or gets a redirect and does not notice.

HarnessOld location2026 location
Claude Codecode.claude.com/docs/en/docs/claude-code/<page> (404s)code.claude.com/docs/en/<page> · index at /docs/llms.txt
Codex CLIdevelopers.openai.com/codex/* (308s) · repo docs/ now stubslearn.chatgpt.com/docs/*
Gemini CLIdocs/cli/configuration.md, docs/core/memport.md, docs/tools/memory.md (404)docs/{cli,core,reference,tools,hooks,extensions}/
Cursor/docs/context/* (301s)/docs/rules, /docs/mcp, /docs/agent/tools/search

1. Claude Code (CLI)

Measured against v2.1.251 on Linux/WSL2 in addition to the docs.

A. Context assembly

Load order, broadest to most specific (CONFIRMED, /docs/en/memory):

ScopePath
Managed policymacOS /Library/Application Support/ClaudeCode/CLAUDE.md · Linux+WSL /etc/claude-code/CLAUDE.md · Windows C:\Program Files\ClaudeCode\CLAUDE.md
User~/.claude/CLAUDE.md
Project./CLAUDE.md or ./.claude/CLAUDE.md
Local./CLAUDE.local.md

These concatenate, they do not override — "All discovered files are concatenated into context rather than overriding each other… ordered from the filesystem root down to your working directory." CLAUDE.local.md is appended after CLAUDE.md within each directory and is not deprecated (CONFIRMED — it is still documented as live).

CLAUDE.md is delivered as a user message after the system prompt, not as part of it (CONFIRMED). Output styles are the thing that modifies the system prompt.

Upward walk, lazy downward. It loads from cwd "and every directory above it." Subdirectory files load only when Claude reads a file in that directory with the Read tool — not at launch, and not when writing or creating files there (CONFIRMED, /docs/en/debug-your-config).

@-imports: @path/to/import, max four hops, relative paths resolve against the file containing the import, @~/.claude/foo.md works. Imports expand at launch — they do not save context.

.claude/rules/*.md (2026 mechanism): without paths: frontmatter they load at launch at the same priority as .claude/CLAUDE.md, user rules before project rules. With paths: they load only when a matching file is read. Brace-expansion budget is 1,000 patterns / 4 MiB; over-budget patterns are used unexpanded and match nothing.

Always vs on-trigger (CONFIRMED, /docs/en/context-window — token counts are the doc's own): system prompt (~4,200) · auto memory MEMORY.md (~680) · environment info (~280) · MCP tool names only (~120, schemas deferred) · skill descriptions only · user then project CLAUDE.md. Full skill bodies load only on use, and once loaded stay in the conversation across later turns.

Documented limits:

LimitValue
CLAUDE.md hard limit4 MiB — a larger file is skipped entirely
CLAUDE.md advisoryunder 200 lines
Auto memory MEMORY.mdfirst 200 lines or 25 KB
Skill description in listingtruncated at 1,536 chars
Skill listing budget1% of context window, fallback 8,000 chars
MCP tool description2 KB each
Number of skillsno documented cap — the budget is the constraint

Compaction. Re-injected from disk: project CLAUDE.md, unscoped rules, auto memory, the plan. Files read come back for up to five files. Invoked skill bodies return at 5,000 tokens each, 25,000 total. Hook-added context is summarized away. The skill listing is the exception nobody expects: it is not re-injected after /compact, so afterwards Claude can auto-invoke only skills it already used this session (CONFIRMED). "Microcompact" appears in no page fetched — UNCONFIRMED.

Showing what is loaded: /context [all] is the answer — a colored grid breaking out system prompt, MCP tools, subagents with the source each loaded from, memory files and skills. /memory lists locations (including files that do not exist yet), not what loaded. /status shows active settings sources. /doctor is now a bundled skill, not a screen.

B. I/O surface

Permission modes (CONFIRMED against the binary): default (alias manual) · acceptEdits · plan · auto · dontAsk · bypassPermissions. Evaluation is deny → ask → allow, first match wins; specificity does not reorder it, so a broad Bash(aws *) deny beats a narrow Bash(aws s3 ls) allow.

Two syntax traps worth memorizing: Bash(ls *) with a space does not match lsof, while Bash(ls*) does. And in Read/Edit rules /path is relative to the settings source, not the filesystem root — //path is the absolute form.

Sandboxing exists on macOS (Seatbelt), Linux and WSL2 (bubblewrap); native Windows and WSL1 are unsupported. Default write is cwd plus --add-dir; default read is the entire computer except denied paths, which still allows ~/.aws/credentials and ~/.ssh/.

MCP scopes: local (default, in ~/.claude.json) · project (.mcp.json at the repo root) · user. Transports http / sse (deprecated) / stdio / ws. Project servers require a one-time approval per machine.

Subagents: .claude/agents/ and ~/.claude/agents/, each with its own context window. Note the inversion — for skills, personal overrides project; for subagents, project outranks user. Built-in Explore and Plan skip CLAUDE.md and git status; custom subagents load it normally.

Hooks: 33 events (CONFIRMED, /docs/en/hooks), including InstructionsLoaded, which fires when a CLAUDE.md or rules file loads and is the documented way to "log exactly which instruction files are loaded, when they load, and why." Exit 2 is an absolute block that overrides JSON and cannot be overridden even by permissionDecision: allow; stderr on exit 0 goes to the debug log only, never to Claude. PreToolUse fires before any permission check in every mode including bypassPermissions — but a hook allow cannot loosen a settings deny.

Headless: claude -p, --output-format text|json|stream-json, --json-schema for structured output, exit 0 / non-zero / 143 on SIGTERM. --bare skips discovery of hooks, skills, commands, subagents, plugins, MCP and CLAUDE.md, and never reads the keychain; it "will become the default for -p in a future release." SDK packages are @anthropic-ai/claude-agent-sdk and claude-agent-sdknot @anthropic-ai/claude-code.

C. State on disk

Verified directly on a live install as well as in the docs.

~/.claude/CLAUDE.md                              user memory
~/.claude/settings.json                          permissions, hooks, env, model
~/.claude/settings.local.json                    written BY Claude Code on "don't ask again"
~/.claude/.credentials.json                      mode 0600 — Linux/WSL/Windows (macOS uses Keychain)
~/.claude/projects/<munged-cwd>/<uuid>.jsonl     full transcript: every message, tool call, result
~/.claude/projects/<project>/memory/MEMORY.md    auto memory, keyed by GIT REPO (worktrees share it)
~/.claude/history.jsonl                          every prompt ever typed, with timestamps
~/.claude/{skills,agents,plugins,shell-snapshots,file-history,state}/
~/.claude.json                                   MCP servers, trust decisions, OAuth account — NOT settings

~/.claude/todos/, statsig/ and logs/ are legacy and no longer written — tooling that reads them is reading a vestige. CLAUDE_CONFIG_DIR relocates all of it.

Never commit: .claude/settings.local.json, CLAUDE.local.md, .credentials.json, anything under ~/.claude/. Note the sharp edge: Claude Code adds settings.local.json to your global git excludes, not the repo's .gitignore — a hand-created file is your problem. And transcripts are not encrypted at rest: if a tool reads a .env, that value is now in the session .jsonl.

D. The most common silent misconfiguration

A skill whose description names a topic rather than an occasion never fires. It appears in /skills, is loaded, listed, and inert, with zero error output. The fix per the docs is to include "keywords users would naturally say."

Four more that fail just as quietly:

  1. Skill descriptions are silently truncated — or dropped. When the listing overflows its 1% budget, Claude Code "drops descriptions starting with the skills you invoke least." A skill that worked can stop working purely because you added other skills.
  2. Malformed skill frontmatter loads the body with empty metadata/skill-name still works, auto-invocation is dead.
  3. ~/.claude.json is not a settings file. permissions, hooks and env put there are simply never read.
  4. In -p and the SDK the trust gate fails open in the wrong direction: the repo's permissions.allow is silently not applied, while its hooks, env, and .mcp.json servers all run.

2. Claude Desktop / claude.ai with connectors

The odd one out: no filesystem of its own, no headless mode, and no way to see what is in context.

A. Context assembly

Three personalization layers, not four (CONFIRMED, support.claude.com): Instructions for Claude (account-wide) · Project instructions (per project) · Skills.

Styles is retired. The article 404s and it is absent from the 79-article collection index; Skills is the successor. Any guide describing Styles is pre-2026.

Precedence between the three is NOT DOCUMENTED (CONFIRMED-NEGATIVE). The personalization page says only that you "can use these features independently or in combination" and never names a conflict winner. Any hierarchy you have seen asserted is inference.

Memory is persistent and stored as individual topics, not a file you can edit — global plus a per-project space. On by default for Free/Pro/Max, off by default for Team/Enterprise. Export is copy/paste text, not a download. Incognito chats write nothing to history or memory.

Projects silently switch to RAG. Retrieval "automatically activates when your project approaches or exceeds the context window limits" — no manual step, up to 10x capacity. The mechanism changes underneath you: instead of whole files in context, Claude uses a project knowledge search tool. There is a binary indicator; a percentage meter is not documented (UNCONFIRMED).

Context window, 2026: Opus 5 and Sonnet 5 run 1M tokens on paid plans; Opus 4.8/4.7/4.6 and Sonnet 4.6 run 500K; others 200K. Free tier is unpublished.

Long conversations now summarize rather than hard-stop — "allows conversations to continue indefinitely in most cases." This is a change from the old behavior, and it is gated on code execution being enabled. Without it you get the old hard error instead.

There is no /context equivalent, no token indicator, no context inspector (CONFIRMED-NEGATIVE). The only signals are the transient "organizing its thoughts" state and the binary RAG indicator.

B. I/O surface

Connectors are remote MCP servers that run from Anthropic's cloud — "your server must be reachable over the public internet," so a firewalled server will never connect. Local servers come in as Desktop Extensions, which are Desktop and Claude Code only — not web, not mobile.

Connection is account-global but loading is per-conversation, with three modes: Auto (default, Claude decides), Always available, On demand. Guidance is under 10 connectors → Always, 10–30 → Auto, 30+ → On demand. "Each conversation setting is independent."

.dxt is now .mcpb and the repo moved out of Anthropic's org — github.com/anthropics/mcpb 301s to modelcontextprotocol/mcpb. The rename date is unpublished, and the on-disk install path for a .mcpb is not documented anywhere (UNCONFIRMED).

macOS    ~/Library/Application Support/Claude/claude_desktop_config.json
Windows  %APPDATA%\Claude\claude_desktop_config.json
Linux    NOT DOCUMENTED — though a Linux beta exists (apt, binary `claude-desktop`)

Hooks exist in the extensibility model but are inert in chat. Verbatim: "Hooks and sub-agents run only in Cowork, so they appear grayed out in chat."

There is no headless mode (CONFIRMED-NEGATIVE). The programmatic path is the Agent SDK or claude -p.

C. State on disk

Conversations are server-side on consumer claude.ai and Desktop. Logs are at ~/Library/Logs/Claude/mcp*.log (macOS) or %APPDATA%\Claude\logs. Org plugins live in /Library/Application Support/Claude/org-plugins/ and C:\Program Files\Claude\org-plugins\.

Beware paths beginning Claude-3p/ in the docs — those are the third-party/BYO-inference build, not consumer Desktop.

D. The most common silent misconfiguration

Editing claude_desktop_config.json without fully quitting the app. Verbatim: "fully quit and reopen; closing the window is not enough." Closing the window looks identical to a restart and loads nothing.

The 2026 runner-up has inverted: Desktop now ships its own Node.js, so a bundled extension can work while a hand-configured stdio server on the same machine fails for PATH reasons — stdio servers "inherit only a limited subset of environment variables," and a GUI app has no shell profile. Use absolute paths and an explicit env block.

Third: project knowledge silently switching to RAG, which degrades any question needing whole-document reasoning without ever raising an error.


3. Cursor (and Cursor CLI)

Three 2026 changes invalidate most existing guides.

A. Context assembly

The CLI binary is agent, not cursor-agent (CONFIRMED — cursor-agent appears zero times in the current CLI docs; the installed build on this machine still uses the old name, so verify with agent --version).

Rules live in .cursor/rules/*.mdc. A plain .md file there is silently ignored because it has no frontmatter — the docs' own example labels it # Ignored (wrong extension).

Three frontmatter keys onlydescription, globs, alwaysApply:

alwaysApplydescriptionglobsBehavior
trueAlways included. Globs and description are ignored.
falseprovidedAuto-attached when a matching file is in context
falseprovidedAgent reads description, pulls it in when relevant
falseOnly via @-mention

Globs are comma-separated. Precedence is Team → Project → User, all merged, "earlier sources take precedence when guidance conflicts." Size guidance is explicit: keep rules under 500 lines.

AGENTS.md is supported at root and nested. CLAUDE.md is read by the CLI and applied as rules.

Embeddings are gone. codebase-indexing now redirects to agent/tools/search: discovery is Instant Grep, "a custom search engine that outperforms ripgrep," plus an Explore subagent with its own context window. The word "embedding" appears nowhere in current docs.

Memories is retired/docs/context/memories redirects to /docs/rules. Do not plan around it.

.cursorrules status: UNCONFIRMED as formally deprecated, on absence-only evidence — zero occurrences across every current page, and not among the four rule types. Treat it as unsupported.

Context usage is visible via the CLI's /context; manual compaction is /summarize (/compact and /compress are aliases). The preCompact hook receives exact numbers but is observational only.

B. I/O surface

🔴 .cursorignore is not a security boundary. Verbatim: "The terminal and MCP server tools used by Agent cannot block access to code governed by .cursorignore." It blocks Agent/Tab/Inline Edit and @-mentions; it does not block cat, grep, any shell command, or any MCP tool. Real enforcement is permissions.json plus the sandbox.

MCP at .cursor/mcp.json and ~/.cursor/mcp.json; stdio, SSE and Streamable HTTP; Roots, Elicitation and Apps all supported; ${env:NAME} interpolation for secrets. The historical ~40-tool cap has no mention in current docs — UNCONFIRMED whether raised, removed, or merely undocumented. Do not assume it is gone; verify with agent mcp list-tools <id>.

Subagents: built-in Explore, Bash and Browser, plus custom ones in .cursor/agents/ — and it also reads .claude/agents/ and .codex/agents/, with .cursor/ winning.

Hooks in .cursor/hooks.json, auto-reloaded, with 18 agent events plus Tab and workspace events. Blocking is {"permission": "deny"} or exit code 2 ("This matches Claude Code behavior"). 🔴 Hooks fail OPEN by default — a crash, timeout or invalid JSON lets the action through unless failClosed: true.

Headless: agent -p, --output-format text|json|stream-json. 🔴 -p alone does not write files — "Without --force, changes are only proposed, not applied." Permission tokens are Shell(cmd), Read(glob), Write(glob), WebFetch(domain), Mcp(server:tool); deny beats allow. Exit codes beyond zero/non-zero are UNCONFIRMED.

C. State on disk

~/.cursor/ holds cli-config.json, mcp.json, hooks.json, permissions.json, sandbox.json, rules (machine-local, not synced), agents/, skills/, worktrees/. Per-OS chat history and credential cache paths are UNCONFIRMED — no such table exists in current docs.

Never commit .cursor/mcp.json with hardcoded secrets, or .cursor/keys. Note that .cursor/cli.json and .cursor/permissions.json are meant to be committed.

D. The most common silent misconfiguration

Omitting alwaysApply turns the rule into a manual-only rule. With no alwaysApply, no description and no globs, it is "included only when you @-mention the rule." The file exists, is valid, shows up in the UI, and never loads.

Then the same failure Claude Code has: an "Apply Intelligently" rule whose description names a topic rather than an occasion is never selected. The docs' own good example is occasion-shaped — "Security specialist. Use when implementing auth, payments, or handling sensitive data."

Third, and purely mechanical: globs: *.ts matches only root-level .ts files, not src/foo.ts. You need **/*.ts.


4. opencode

Open source, so the source is authoritative — and it contradicts its own published docs in four places. Findings below are from sst/opencode@dev, v1.18.25 (2026-08-28).

A. Context assembly

Resolution order from packages/opencode/src/session/instruction.ts:

  1. Global: ~/.config/opencode/AGENTS.md, else ~/.claude/CLAUDE.md — it breaks on the first that exists, so the two are mutually exclusive.
  2. Project: for each of AGENTS.md, CLAUDE.md, CONTEXT.md in order, findUp from cwd to the git worktree root; on the first name with any match it adds all matches and stops. The source comment: "The first project-level match wins so we don't stack AGENTS.md/CLAUDE.md from every ancestor." Name precedence beats proximity.
  3. The instructions config array, appended after.

🔴 DOCS-WRONG #1. opencode.ai/docs/rules says opencode "does not automatically scan subdirectory AGENTS.md files." The source implements lazy nested loading: when the read tool reads a file, it walks upward from that file's directory and attaches any instruction file found, deduped per assistant message. Subdirectory AGENTS.md is read — on trigger, not always.

Config merges global (config.jsonopencode.jsonopencode.jsonc) then project files walked up and reversed, so the config nearest cwd wins. XDG variables are honored. macOS MDM managed preferences override everything.

Auto-compaction is on by default with no percentage threshold — it fires when tokens reach usable(), computed from the model's limits minus a reserve. Constants are explicit in compaction.ts (PRUNE_MINIMUM 20,000; preserve-recent clamped 2,000–15,000).

No TUI token indicator and no "show loaded context" command established — UNCONFIRMED.

B. I/O surface

Permission keys are read, edit, glob, grep, list, bash, task, external_directory, todowrite, question, webfetch, websearch, lsp, doom_loop, skill — plus arbitrary keys, since the schema carries a rest-record. Values are ask / allow / deny.

🔴 Matching uses findLast — the LAST matching rule wins, so catch-alls must come first. Config parsing preserves key order specifically for this.

🔴 DOCS-WRONG #2. The docs say "most permissions default to allow" and that .env reads are denied. The evaluator's fallback is ask; the permissiveness comes from a built-in defaults ruleset ("*": "allow"), and .env reads are ask, not deny — anyone relying on the docs for secret hygiene is unprotected.

🔴 DOCS-WRONG #3. The docs list a built-in Scout subagent. It does not exist in dev source.

🔴 DOCS-WRONG #4. Agent and command directories accept both singular and plural ({agent,agents}, {command,commands}, {plugin,plugins}), and nested subdirectories are scanned.

There is no URL allowlist. webfetch is typed as an action-only permission that does not even accept patterns. Remote instructions URLs bypass the tool permission system entirely.

Plugins are .ts or .js in any config dir, with ~20 hooks including permission.ask (plugins can auto-approve) and tool (plugins can define custom tools). Note the docs' event list (session.created, file.edited) is a different axis from the hook names.

Headless: opencode run "prompt", --format default|json where JSON is a raw event stream, not one document. Exit codes are only 0 and 1 — no per-failure-class codes, confirmed by exhaustive grep. opencode serve exposes an OpenAPI 3.1 HTTP server on port 4096; the TUI itself is a client of it.

C. State on disk

~/.local/share/opencode/auth.json      credentials — NEVER COMMIT
~/.local/share/opencode/{log,project,plans,repos}/
~/.config/opencode/{opencode.json,AGENTS.md,agent[s]/,command[s]/,plugin[s]/,skills/}
~/.local/state/opencode/               lock state (in source, NOT documented)

opencode auto-creates a .gitignore inside .opencode/ for plugin scaffolding only — your opencode.json, agents, commands and plans there are meant to be committed.

D. The most common silent misconfiguration

Unknown and typo'd config keys are silently absorbed, not rejected. The schema is StructWithRest(Struct({...}), [Record(String, Any)]), and normalize() sweeps every unrecognized key into agent.options. A typo'd descripton: or permissions: (the correct key is singular, permission) does not error, does not warn — it becomes an inert provider option. $schema gives editor completion only; it is not enforced at load.

Two more, both pure silence: an AGENTS.md anywhere up-tree suppresses your CLAUDE.md entirely (the loop breaks on the first name), and relative instructions paths are glob-walked up from cwd, so they resolve differently depending on which subdirectory you launched from — a miss returns empty, and a remote URL fails silently after a 5-second timeout.


5. Codex CLI (OpenAI)

The repo docs/ directory is now stubsdocs/config.md is 726 bytes, docs/sandbox.md 150. The root AGENTS.md states the rule: "Do not add general product or user-facing documentation to the docs/ folder." Canonical docs are at learn.chatgpt.com/docs/; findings below are cross-checked against codex-rs source.

A. Context assembly

Load order (codex-rs/core/src/agents_md.rs):

  1. Global ~/.codex/AGENTS.override.md, else ~/.codex/AGENTS.md — first non-empty only. AGENTS.override.md is new in 2026.
  2. Project, walking up from cwd to the project root (detected by project_root_markers, default [".git"]), then concatenated root-first, cwd-last — so nearer files win by position in the prompt, not by replacing.
  3. At most one file per directory.

🔴 An untrusted project loads no project AGENTS.md at all — the loader returns before reading any project file, and .codex/config.toml and project hooks are skipped too. The session looks completely normal.

~/.codex/instructions.md is confirmed REMOVED — zero hits in source as a user instruction file.

project_doc_max_bytes is 32768 (confirmed three ways: defaults.toml, config.schema.json, DEFAULT_PROJECT_DOC_MAX_BYTES: usize = 32 * 1024).

Config precedence, highest first: CLI -c flags → project .codex/config.toml (trusted only) → profile file $CODEX_HOME/<name>.config.toml~/.codex/config.toml/etc/codex/config.toml → defaults. Project configs are deliberately powerless over approval_policy, sandbox_mode, model_provider, notify and otel.

Skills exist in 2026 and are not under .codex — they live at .agents/skills, $REPO_ROOT/.agents/skills, $HOME/.agents/skills and /etc/codex/skills, with a description budget of "at most 2% of the model's context window, or 8,000 characters." Explicit invocation is $skill.

/status, /context and /compact exist; the auto-compaction key is model_auto_compact_token_limit.

B. I/O surface

sandbox_mode: read-only · workspace-write · danger-full-access. codex exec defaults to read-only. approval_policy: untrusted · on-request · neveron-failure is gone, replaced by an optional granular table.

🔴 The platform mechanism is not what older guides say. macOS uses Seatbelt; Linux and WSL2 use bubblewrap, not Landlock+seccomp; Windows uses native Windows Sandbox. The old claim that WSL has no sandbox is wrong — but if bwrap is not on PATH, sandboxing cannot be enforced.

Network is disabled by default in workspace-write (serde default false). Enable via [sandbox_workspace_write] network_access = true. Sandboxed children get CODEX_SANDBOX_NETWORK_DISABLED=1, which is the reliable in-process detector.

MCP under [mcp_servers.<id>], stdio or HTTP, startup_timeout_sec 10 and tool_timeout_sec 60. Codex as an MCP server is UNCONFIRMED.

Web search is no longer a boolean: [tools] web_search = "cached" by default, from disabled | cached | indexed | live.

Subagents exist[features] multi_agent defaults true, with /agent and /subagents and DEFAULT_AGENT_MAX_THREADS = Some(6).

Hooks are real in 2026 (not merely notify): hooks.json or inline [hooks] with [[hooks.PreToolUse]] matchers, gated by [features] hooks.

Headless: codex exec "prompt" — progress to stderr, final message to stdout. --json emits JSONL (thread.started, item.*, turn.completed); --output-last-message, --output-schema, --ephemeral, and codex exec resume. Numbered exit codes are UNCONFIRMED. SDKs: @openai/codex-sdk and, new, Python openai-codex.

C. State on disk

~/.codex/config.toml
~/.codex/auth.json                                          credentials — NEVER COMMIT
~/.codex/sessions/YYYY/MM/DD/rollout-<ts>-<uuid>.jsonl      transcripts
~/.codex/history.jsonl
~/.codex/prompts/*.md                                       custom /name prompts
$HOME/.agents/skills                                        skills — OUTSIDE CODEX_HOME

🔴 ~/.codex/log/codex-tui.log does not exist by default in 2026 — "the TUI records diagnostics in bounded local stores by default. Set log_dir explicitly to enable a plaintext TUI log." Windows native paths are UNCONFIRMED.

D. The most common silent misconfiguration

AGENTS.md truncation, and it is worse than a clean skip. The 32,768-byte budget is a shared running total consumed root-first, and overflow is a mid-byte data.truncate():

  • A large repo-root AGENTS.md starves the cwd-level file that was supposed to override it — the precedence model inverts exactly where you rely on it.
  • The cut lands mid-sentence, so the model reads a syntactically valid, semantically corrupted file.
  • The only signal is a tracing::warn!, and the TUI writes no plaintext log by default, so you cannot see the warning without first setting log_dir.

Runner-up: the untrusted-project silent drop described in section A. Third: allow_managed_hooks_only works only in requirements.toml — set in config.toml it silently does nothing, so an admin believes hooks are locked down when they are not.


6. Gemini CLI (Google)

In 2026 this has hooks, subagents, skills and plan mode — capabilities most guides still treat as absent.

A. Context assembly

Three tiers, in load order (docs/cli/gemini-md.md): global ~/.gemini/GEMINI.md → workspace GEMINI.md in configured dirs and their parentsjust-in-time GEMINI.md discovered when tools touch a file, scanning up to a trusted root. The old "eagerly walk down every subdirectory" model is superseded. Bounded by context.discoveryMaxDirs (default 200).

context.fileName takes a string or an array and is nested: { "context": { "fileName": ["AGENTS.md", "CONTEXT.md", "GEMINI.md"] } }.

Imports use @./x.md with circular detection and max depth 5. The context.importFormat enum values are UNCONFIRMED.

Settings precedence, lowest to highest: defaults → system-defaults.json~/.gemini/settings.json.gemini/settings.jsonsystem settings file → env / .env → CLI args. 🔴 Note the trap: the system settings file overrides both user and project, the reverse of the usual intuition.

OSSystem settings
Linux/etc/gemini-cli/settings.json
WindowsC:\ProgramData\gemini-cli\settings.json
macOS/Library/Application Support/GeminiCli/settings.json

The schema is nested v3 (general.*, context.*, tools.*, security.*, hooksConfig.*), and migration is active — deprecated flat keys are rewritten where writable, warned where the config is read-only.

/memory has exactly four subcommands: show, reload, list, inbox (read from memoryCommand.ts). There is no /memory add and no /memory refreshreload is the name.

Compression is /compress, auto-triggered at model.compressionThreshold (default 0.5), with a PreCompress hook. The footer context percentage is hidden by default (ui.footer.hideContextPercentage defaults true). What survives compression is UNCONFIRMED.

.geminiignore requires a session restart to take effect.

B. I/O surface

Tools are read_file, write_file, replace, glob, grep_search, read_many_files, run_shell_command, web_fetch, google_web_search, write_todos.

Sandbox via GEMINI_SANDBOX = true|docker|podman|sandbox-exec|runsc|lxc, image ghcr.io/google/gemini-cli:latest, six macOS Seatbelt profiles. tools.sandboxNetworkAccess defaults false.

MCP under mcpServers with command/args/env/cwd/timeout/trust/url/httpUrl/ headers/includeTools/excludeTools. excludeTools takes precedence over includeTools. web_fetch handles up to 20 URLs per prompt. No proxy key found — UNCONFIRMED.

Subagents exist: .gemini/agents/*.md and ~/.gemini/agents/*.md, required frontmatter name, description, kind, plus tools, model, max_turns. Invoked automatically or via @agent_name. Subagents cannot call other subagents.

Hooks: eleven eventsSessionStart, SessionEnd, BeforeAgent, AfterAgent, BeforeModel, AfterModel, BeforeToolSelection, BeforeTool, AfterTool, PreCompress, Notification. The config shape mirrors Claude Code's, and exit 2 is a hard block. stdout must carry nothing but the final JSON object — debug output goes to stderr or it corrupts the contract. It even sets a CLAUDE_PROJECT_DIR compatibility alias.

Headless: gemini -p, -o/--output-format text|json|stream-json, --approval-mode default|auto_edit|yolo|plan. --yolo and --allowed-tools are deprecated, and --checkpointing was removed in v0.11.0. Exit codes are enumerated — the only harness here that does: 0 ok, 1 general, 41 auth, 42 input validation, 44 sandboxing, 52 config, 53 turn limit.

C. State on disk

~/.gemini/settings.json          ~/.gemini/GEMINI.md
~/.gemini/oauth_creds.json       SECRET — never commit
~/.gemini/mcp-oauth-tokens.json  SECRET
~/.gemini/a2a-oauth-tokens.json  SECRET
~/.gemini/trustedFolders.json    ~/.gemini/{commands,skills,agents,extensions}/
~/.gemini/tmp/<id>/              checkpoints, shell_history, chats/, memory
~/.gemini/history/<id>           a SHADOW GIT REPO used for checkpointing

<id> is now a short id from a ProjectRegistry, not the raw sha256 — storage.ts carries migration code from the old hash. The user directory is ~/.gemini on all platforms; only the system config directory differs.

D. The most common silent misconfiguration

Setting context.fileName replaces the default rather than extending it. Set it to "AGENTS.md" and every GEMINI.md in the tree stops loading, with no warning. Use the array form to keep both.

Close second: folder trust silently disables nearly everything. In an untrusted folder the workspace .gemini/settings.json is ignored, .env is ignored, MCP servers do not connect, custom commands are not loaded and memory is not auto-loaded. The project simply behaves as though none of its configuration exists. Note the docs disagree with themselves on the default here — the generated settings table says security.folderTrust.enabled defaults true while the trusted-folders page presents it as opt-in; treat the generated table as authoritative.

Third: "trust": true on an MCP server bypasses every confirmation for that server's tools.


Comparison

Always-loaded fileOn-trigger mechanismTool protocolHeadlessHooks
Claude Code~/.claude/CLAUDE.md, ./CLAUDE.md, ./CLAUDE.local.md, .claude/rules/*.md (concatenated)Skills (description → body); rules with paths:; subdir CLAUDE.md on ReadMCP (stdio/http/sse/ws), 3 scopesclaude -p, text/json/stream-json, --json-schema, exit 143 on SIGTERM33 events, exit 2 = absolute block
Claude DesktopInstructions for Claude · Project instructions · Memory topicsSkills (zip upload); connectors per-conversation (Auto/Always/On demand); RAG auto-switchMCP connectors (cloud-run) + .mcpb extensionsNonePresent but inert in chat ("run only in Cowork")
Cursor.cursor/rules/*.mdc with alwaysApply: true; AGENTS.md; User/Team rulesAuto Attached (globs); Agent Requested (description); @-mentionMCP (stdio/SSE/HTTP), .cursor/mcp.jsonagent -pneeds --force to write~21 events, .cursor/hooks.json, fail-open
opencode~/.config/opencode/AGENTS.md or ~/.claude/CLAUDE.md; first project-level name matchNested AGENTS.md on read; skills via skill toolMCP local/remote in opencode.jsonopencode run, --format json (event stream), exit 0/1 only~20 plugin hooks incl. permission.ask, custom tools
Codex CLI~/.codex/AGENTS.md; project AGENTS.md root-first (32 KB shared budget)Skills at .agents/skills ($skill); ~/.codex/prompts/*.mdMCP [mcp_servers.*] in config.tomlcodex exec, --json JSONL, exit codes UNCONFIRMEDReal in 2026, hooks.json + [hooks], plus notify
Gemini CLI~/.gemini/GEMINI.md + workspace/parentsJIT GEMINI.md on tool touch; skills; .gemini/commands/*.tomlMCP mcpServers (stdio/SSE/HTTP)gemini -p, --output-format json, enumerated exit codes11 events, exit 2 = hard block

The one-line version of each silent failure

HarnessWhat looks fine and is not
Claude CodeA skill description naming a topic not an occasion never fires — and descriptions get dropped when you add more skills
Claude DesktopConfig edited without fully quitting; project knowledge silently switching to RAG
CursoralwaysApply omitted makes the rule manual-only; -p without --force writes nothing and exits 0
opencodeTypo'd config keys are silently absorbed into an inert options bag; $schema is not enforced
Codex CLIAGENTS.md truncated mid-sentence against a shared 32 KB budget, warned only to a log that does not exist by default
Gemini CLIcontext.fileName replaces the default, so every GEMINI.md silently stops loading

What this page does not establish

Named explicitly, because a gap is more useful than a guess:

  • Whether Claude Code's CLAUDE.md walk stops at the repo root or continues to /; "microcompact" appears in no current doc.
  • Claude Desktop: the .mcpb on-disk install path, the Linux config path, free-plan context size, and whether Claude is told it is in RAG mode.
  • Cursor: the current MCP tool cap, an explicit .cursorrules deprecation statement, per-OS history paths, and an exit-code table.
  • opencode: whether the TUI shows a token indicator, and the exact env-var literals behind its project-config kill switch.
  • Codex CLI: numbered exit codes, Windows-native CODEX_HOME, and whether experimental_instructions_file still exists.
  • Gemini CLI: context.importFormat values, a proxy key, and what survives /compress.

On this page