CodeVetter · Repo Unpack · Data flow
anthropics/claude-code
Mod data never touches the network except telemetry's batch POST and security-guidance's model call. Instruction files, diffs, and settings move through the engine nouns $.fs, $.session, $.settings, $.process, $.store, and $.ui. Plugin hooks speak JSON on stdin/stdout. Issue bots speak the GitHub REST API with GITHUB_TOKEN and, separately, Statsig. Identity for analytics is read from ~/.claude.json (or CLAUDE_CONFIG_DIR) and account fields are only kept on an internal build.
- agents-md prompt.context input is e.instructionFiles (kinds managed, user, project, local, memory). It calls $.session.root and $.fs.ancestors, drops files already present by path or content, and returns next({...e, instructionFiles}). The engine, not the plugin, renders claudeMd. A hook above this mod has the last word because sec-default continues prompt.context to the append tier.
- On Read, agents-md resolves ~ via HOME or USERPROFILE (profile first when cwd contains a backslash), walks ancestors below the live $.session.root, and appends Frames.nestedFrame entries onto result.context. Per-loop delivery is a Map from agent id to a Set of paths, copied on agent.spawn when fork is true.
- telemetry register builds Sender in engine.create from the beneath engine: session.authorize/id/model/surfaces/cwd/repo, env.get of a large fixed name list, settings.read({source:'policy'}), fs.read/list/exists, process.run, clock.after/sleep, http.fetch, ui.log. log/mark call Entries.checkedFields/checkedMark then queue. flush runs on session.end, at BATCH_ROWS 100, or BATCH_WINDOW_MS 5000 after the first queued row.
- Each telemetry batch re-reads switches. isAnalyticsOff returns true (send nothing) when NODE_ENV is test, DISABLE_TELEMETRY or CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC is set, DO_NOT_TRACK is truthy, an unmanaged third-party flag is on (CLAUDE_CODE_USE_BEDROCK, USE_VERTEX, USE_FOUNDRY, USE_ANTHROPIC_AWS, USE_ANTHROPIC_GOOGLE_CLOUD, USE_MANTLE) unless CLAUDE_CODE_PROVIDER_MANAGED_BY_HOST, a gateway is forced (CLAUDE_CODE_USE_GATEWAY or policy forceLoginMethod gateway / forceLoginGatewayUrl), or CLAUDE_CODE_CUSTOM_OAUTH_URL is set. Unreadable switches also send nothing. No authorization handle drops the batch.
- The POST body is Entries.batchOf(rows) with session id, model, userType ant if USER_TYPE is ant else external, and a context gathered once. HTTP is method POST, Content-Type application/json, x-service-name claude-code, auth the authorize() handle, URL INGEST_URL. Retriable statuses (server error, 408, 429) sleep RETRY_DELAY_MS 500 and post once more.
- Identity for a row is JSON.parse of globalConfigPath: CLAUDE_CONFIG_DIR or HOME or USERPROFILE plus .claude.json. identityOf reads record.userID and record.oauthAccount. A missing, unreadable, or non-JSON file yields an empty identity; the address is kept on an internal build alone.
- Once per session, off Windows, telemetry runs one shell script via process.run: uname -s, uname -r, uname -m, then command -v for npm/yarn/pnpm and bun/deno/node. The register.ts call uses timeout Context.PROBE_TIMEOUT_MS. Env vars that name secrets, people, or hosts are recorded only as set-or-not (IsAnalyticsOff.isEnvSet).
- Diff pins a git backend with one rev-parse in the session cwd, then every later git child is argv ['git', --git-dir=<gitDir>, --work-tree=<toplevel>, ...argv] with cwd toplevel, GIT_CHILD_ENV, and Limits.GIT_TIMEOUT_MS. backendOf asks INSTALLED_BACKEND_PROBES first (empty set as shipped) then Git.gitBackendOf. The chosen base mode is store.get/store.set keyed by repository toplevel.
- Diff UI data flow: ui.render of Pane calls $.ui.resolve for Box, Text, Button, Select, Code and returns Views.paneView. ui.scroll on the docked pane updates model.place and returns {} so the engine window stays still. prompt.submit appends Ask.fittedAskTextOf to e.context when an ask is armed and the text fits under Limits.PROMPT_CONTEXT_MAX_CHARS; otherwise it disarms and sets a status line.
- security-guidance main() reads one JSON object from stdin (session_id, tool_name, tool_input, hook_event_name, cwd). PostToolUse edits run check_patterns and may print hookSpecificOutput.additionalContext. Stop and git commit/push call the LLM path. llm.py posts to ANTHROPIC_BASE_URL (default https://api.anthropic.com) plus /v1/messages. Debug state goes to ~/.claude/security/log.txt (override SECURITY_GUIDANCE_DEBUG_LOG), rotating at 1 MB, and is not uploaded.
- Org guidance for reviews is concatenated from ~/.claude/claude-security-guidance.md, <cwd>/.claude/claude-security-guidance.md, and the .local.md variant, capped so the tail drops first. Custom regex/substring rules load from security-patterns.yaml/json on the same three-level search. extensibility.load_for_session(cwd) runs once per hook invocation and failures are non-fatal.
- hookify PreToolUse reads stdin JSON, maps tool_name Bash to event bash and Edit/Write/MultiEdit to event file, load_rules(event), and prints RuleEngine.evaluate_rules JSON. Import or runtime errors print a systemMessage and still sys.exit(0), so a broken hook does not deny the tool.
- Issue label flow: a labeled event sets env LABEL and ISSUE_NUMBER; lifecycle-comment.ts looks up lifecycle and POSTs a comment to https://api.github.com/repos/${GITHUB_REPOSITORY}/issues/${n}/comments. sweep.ts pages /repos/{owner}/{repo}/issues, skips PRs, locked issues, assignees, and reactions +1 >= 10, then POSTs labels and later PATCH state closed. Triage is constrained to scripts/gh.sh, which forces GH_HOST=github.com and GH_REPO to a single owner/repo and rejects search qualifiers repo:, org:, and user:.
- Statsig is a side channel, not the product telemetry mod. log-issue-events.yml curls https://events.statsigapi.net/v1/log_event on issue opened with statsig-api-key from STATSIG_API_KEY and metadata issue_number, repository, title, author, created_at. claude-dedupe-issues.yml logs github_duplicate_comment_added the same way and skips if the key is empty. auto-close-duplicates.yml passes STATSIG_API_KEY into the Bun script.