This document provides an exhaustive analysis of Claude Code's four core utility subsystems:
- Ultraplan — Multi-step task planning in remote CCR (Claude Code Remote) sessions
- DeepLink — OS-level URI scheme handling (
claude-cli://) for launching sessions - DXT — Plugin/extension packaging format and manifest validation
- FilePersistence — File upload and persistence from local BYOC environments
These systems represent critical integration points in Claude Code's architecture, handling everything from session initialization to plugin distribution to file synchronization. Analysis is based on complete source inspection across 12 files.
Ultraplan is a multi-step task execution system that extends Claude Code's planning capabilities to remote CCR (Claude Code Remote) containers. When a user types the keyword "ultraplan" in a prompt, Claude Code:
- Launches a dedicated remote session in a browser-based UI
- Instructs the remote Claude to plan multi-step tasks
- Shows the user an approval/rejection interface in a PlanModal
- Returns the approved plan to the local session for execution
The system is implemented across two files:
ultraplan/ccrSession.ts— Event polling, plan extraction, phase trackingultraplan/keyword.ts— Trigger detection, keyword filtering
A pure stateful classifier that ingests SDK message streams and tracks ExitPlanMode verdicts:
class ExitPlanModeScanner {
private exitPlanCalls: string[] = [] // Tool use IDs for ExitPlanMode calls
private results = new Map<string, ToolResultBlockParam>() // tool_use_id → tool_result
private rejectedIds = new Set<string>() // Rejected plans (user said "no")
private terminated: { subtype: string } | null // Error subtypes (error_max_turns, etc)
private rescanAfterRejection = false
everSeenPending = false // Lifecycle tracking for diagnostics
}Invariant: The scanner maintains a bidirectional mapping of tool use IDs to their results, tracking rejections in a separate set so the state machine can distinguish between "pending approval," "rejected and trying again," and "approved."
Represents the outcome of processing a batch of new events:
type ScanResult =
| { kind: 'approved'; plan: string } // User approved in CCR
| { kind: 'teleport'; plan: string } // User approved locally (plan in rejection)
| { kind: 'rejected'; id: string } // User explicitly rejected
| { kind: 'pending' } // Waiting for user decision
| { kind: 'terminated'; subtype: string } // CCR session ended
| { kind: 'unchanged' } // No new status infoRepresents the pill/detail-view state for the UI:
type UltraplanPhase = 'running' | 'needs_input' | 'plan_ready'Transitions:
running→needs_input(turn ends, no ExitPlanMode call yet)needs_input→running(user replies in browser)running→plan_ready(ExitPlanMode emitted, no result yet)plan_ready→running(rejected)plan_ready→ (session ends, return approved plan)
The core logic for ingesting a batch of SDKMessages and computing the next state (lines 101-180).
Algorithm:
- Scan all
assistantmessages forEXIT_PLAN_MODE_V2_TOOL_NAMEtool_use blocks → append toexitPlanCalls - Scan all
usermessages for tool_result blocks → store in results Map - Detect
resultevents (turn-end signals) with non-success subtypes → markterminated - Decision precedence (lines 135-161):
- If new events or recent rejection: rescan from the latest non-rejected ExitPlanMode call
- Approved > Teleport > Rejected > Pending > Unchanged
- A single batch can contain both an approved result AND a subsequent terminated event; the approved plan is preserved
Key insight: pollRemoteSessionEvents paginates up to 50 pages per call, spanning seconds of CCR activity. A batch may contain multiple state transitions. The scanner handles this by scanning backward through exitPlanCalls, finding the last non-rejected ID, and checking if a result exists for it.
Two separate extraction functions handle the two approval paths:
Scrapes plan text from approved tool_result content using markers:
// Markers (in preference order):
// "## Approved Plan (edited by user):\n<text>"
// "## Approved Plan:\n<text>"When the ExitPlanModeV2Tool is invoked with default action, the remote writes the plan to a file inside CCR and calls ExitPlanMode({allowedPrompts}). The tool result echoes the plan back with a marker so local can extract it.
Error handling: Throws if neither marker is found — indicates the remote hit the empty-plan or isAgent branch, suggesting misconfiguration.
For the "teleport" path: when the user clicks "execute here" in the browser, the remote sends a rejection (is_error === true) with a sentinel marker:
const ULTRAPLAN_TELEPORT_SENTINEL = '__ULTRAPLAN_TELEPORT_LOCAL__'The plan text follows on the next line. Returns null if sentinel absent, so callers treat it as a normal rejection.
Entry point (lines 198-306) for listening to a CCR session until user approval or timeout.
Arguments:
sessionId— Remote session IDtimeoutMs— Poll deadlineonPhaseChange— Callback for UI updatesshouldStop— Caller's abort signal
Algorithm:
- Create scanner and cursor (null)
- Loop until deadline or approval:
- Call
pollRemoteSessionEvents(sessionId, cursor)with 3s backoff on transient failures - Max 5 consecutive failures → throws
UltraplanPollError('network_or_unknown') - Ingest new events, update cursor
- Check phase (lines 283-295):
scanner.hasPendingPlan→ phase = 'plan_ready'- else
(sessionStatus === 'idle' || 'requires_action') && newEvents.length === 0→ phase = 'needs_input' - else phase = 'running'
- Emit phase change callback if different
- Return on approved/teleport
- Throw on terminated
- Call
- If timeout: throw based on everSeenPending flag to distinguish "never reached ExitPlanMode" (session startup failure) from "user rejected repeatedly"
Key implementation detail: The "quiet idle" check (line 283-285) is crucial. CCR briefly flips to 'idle' between tool turns. The scanner only trusts idle when newEvents.length === 0, so the phase snaps back to 'running' on the first poll that sees the user's reply event, even if session_status lags.
The keyword module (ultraplan/keyword.ts) provides filtered trigger detection to prevent false positives.
Function findKeywordTriggerPositions(text, keyword) detects "ultraplan" and "ultrareview" while skipping:
Exclusion rules:
- Quoted contexts: Inside paired delimiters (backticks, quotes, angle brackets, braces, brackets, parens)
- Single quotes treated specially: only delimit if not apostrophe (non-word char before/after)
- Path/identifier context: Preceded/followed by
/,\,-, or followed by.+ word char- Prevents
src/ultraplan/foo.ts,--ultraplan-mode,ultraplan.tsxfrom triggering
- Prevents
- Questions: Followed by
?(don't invoke on "what is ultraplan?") - Slash commands: Text starting with
/is routed to processSlashCommand, not keyword detection/rename ultraplan foodoesn't trigger
Output: Returns array of { word, start, end } positions, matching the shape of thinking trigger positions.
findUltraplanTriggerPositions(text)— Array of triggersfindUltrareviewTriggerPositions(text)— Array of triggershasUltraplanKeyword(text)— Boolean checkhasUltrareviewKeyword(text)— Boolean checkreplaceUltraplanKeyword(text)— Replace first trigger "ultraplan" → "plan", preserving casing
Custom error with structured failure reason:
type PollFailReason =
| 'terminated' // CCR session ended
| 'timeout_pending' // Timeout after seeing ExitPlanMode
| 'timeout_no_plan' // Timeout before ExitPlanMode
| 'extract_marker_missing' // Extraction failed (malformed result)
| 'network_or_unknown' // Network issues or unknown errors
| 'stopped' // Caller invoked shouldStop()Includes rejectCount so callers know how many rejections user made before giving up.
Ultraplan is initiated when:
- User types "ultraplan" in prompt → keyword detection fires
replaceUltraplanKeyword()modifies the prompt to "please plan..." (singular)- Main session calls
teleportToRemote()with set_permission_mode control_request to enter plan mode - Remote Claude shows ExitPlanModeV2Tool in the toolbox
- Local calls
pollForApprovedExitPlanMode()in a background thread - UI shows PlanModal with approval/rejection buttons
- Poll returns
{ plan, rejectCount, executionTarget } - Plan is either executed locally or archived (if teleport)
DeepLink enables external applications (browsers, documentation sites, CI/CD systems) to launch Claude Code sessions with pre-filled prompts and working directories via the claude-cli:// URI scheme.
Example URIs:
claude-cli://open
claude-cli://open?q=hello+world
claude-cli://open?q=fix+tests&repo=owner/repo
claude-cli://open?cwd=/path/to/project
The system is implemented across six files:
deepLink/parseDeepLink.ts— URI parsing and validationdeepLink/protocolHandler.ts— OS callback routingdeepLink/registerProtocol.ts— OS registration (macOS/Linux/Windows)deepLink/terminalLauncher.ts— Terminal detection and subprocess spawningdeepLink/terminalPreference.ts— Preference persistencedeepLink/banner.ts— Security warning banner
type DeepLinkAction = {
query?: string // Pre-filled prompt (not auto-submitted)
cwd?: string // Working directory (absolute path)
repo?: string // GitHub owner/repo slug, resolved against MRU
}Input validation pipeline:
- Protocol check: Must be
claude-cli://orclaude-cli:(with fallback normalization) - Hostname validation: Must be
open - CWD validation:
- Must be absolute (starts with
/orX:\on Windows) - No control characters (0x00-0x1F, 0x7F) — prevents command injection
- Max 4096 bytes (PATH_MAX)
- Must be absolute (starts with
- Repo slug validation:
- Pattern:
^[\w.-]+/[\w.-]+$(exactly one slash) - Prevents path traversal
- Pattern:
- Query validation:
- Sanitized with
partiallySanitizeUnicode()to strip hidden characters (zero-width spaces, RTL markers, etc.) - No control characters
- Max 5000 bytes (Windows cmd.exe 8191 limit after wrapping + expansion)
- Sanitized with
Error handling: All validation errors throw descriptive messages so the OS UI can show the user why the link failed.
Reverse of parsing — constructs a claude-cli://open URL from an action object.
Entry point when OS invokes claude --handle-uri <url>. Runs in headless context (no TTY).
Algorithm:
- Parse URI via parseDeepLink()
- Resolve cwd via resolveCwd() (precedence: explicit > repo lookup > home)
- If repo was resolved, read last git fetch time (FETCH_HEAD mtime)
- Launch terminal via launchInTerminal(), passing:
- claudePath (process.execPath, the running binary)
- query, cwd, repo, lastFetchMs
- Return exit code (0 = success, 1 = error)
Implements three-tier precedence:
- Explicit cwd: Use as-is
- Repo slug: Look up in
githubRepoPathsconfig (MRU list), return first existing path - Fallback: Use home directory
Returns tuple { cwd, resolvedRepo? } so launched instance knows which clone was selected (for banner freshness warnings).
macOS-specific: when the OS launches Claude as the app bundle's executable via URL handler, uses NAPI module to read the Apple Event:
if (process.env.__CFBundleIdentifier === MACOS_BUNDLE_ID) {
const { waitForUrlEvent } = await import('url-handler-napi')
const url = waitForUrlEvent(5000)
return await handleDeepLinkUri(url)
}Returns null if not a URL launch (normal CLI invocation).
Creates a minimal .app bundle in ~/Applications/Claude Code URL Handler.app:
Components:
Info.plist— Declares CFBundleURLTypes with schemeclaude-cliContents/MacOS/claude— Symlink to the signed claude binary (avoids shipping separate executable)- LaunchServices registration via
/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister
Why symlink? Avoids shipping a separate binary that would need signing and allowlisting by endpoint security tools (Santa, etc).
Commit marker: The symlink is written LAST among throwing fs calls. If Info.plist write fails, no symlink exists → isProtocolHandlerCurrent returns false → next session retries.
Creates .desktop file in $XDG_DATA_HOME/applications/ (default ~/.local/share/applications/):
[Desktop Entry]
Name=Claude Code URL Handler
Comment=Handle claude-cli:// deep links for Claude Code
Exec="/path/to/claude" --handle-uri %u
Type=Application
MimeType=x-scheme-handler/claude-cli;Registers via xdg-mime default:
xdg-mime default claude-code-url-handler.desktop x-scheme-handler/claude-cliHeadless handling: On WSL/Docker/CI where xdg-utils isn't installed, the .desktop file is enough (some apps read MimeType directly). No failure — artifact check short-circuits next session.
Three registry keys under HKEY_CURRENT_USER\Software\Classes\claude-cli:
- Default value:
URL:Claude Code URL Handler URL Protocolkey: empty stringshell\open\commanddefault value:"C:\path\to\claude.exe" --handle-uri "%1"
All written via reg add with /f (force) flag.
Verifies registration is up-to-date by reading back the artifact:
- macOS: Readlink symlink target, compare with expected binary path
- Linux: Read .desktop Exec line, check for exact match
- Windows: Query registry, check command value
Why read back? Install paths can change (installer update, different method) or artifacts can be deleted. Reading detects stale registrations so they self-heal.
Fire-and-forget background task that:
- Checks feature flag
tengu_lodestone_enabled - Checks if registration is current
- If stale/missing, attempts registration
- On EACCES/ENOSPC (deterministic errors), writes failure marker with 24h backoff to prevent spam
Platform-specific, ordered by preference:
macOS (lines 64-121):
- Check stored preference from previous interactive session (TERM_PROGRAM env var)
- Check
$TERM_PROGRAMenv var (iTerm, Ghostty, etc) - Use mdfind (Spotlight) to check installed bundles by bundle ID
- Fallback: check /Applications directly
- Last resort: Terminal.app (always available)
Linux (lines 127-152):
- Check
$TERMINALenv var - Check
x-terminal-emulatoralternative - Walk priority list: ghostty, kitty, alacritty, wezterm, gnome-terminal, konsole, xfce4-terminal, mate-terminal, tilix, xterm
Windows (lines 157-178):
- Windows Terminal (wt.exe) — modern, preferred
- PowerShell 7+ (pwsh.exe) — separate install
- Windows PowerShell 5.1 (powershell.exe) — built-in
- cmd.exe — always available
Two fundamentally different approaches based on terminal capabilities:
Pure argv (no shell, no quoting needed):
- macOS: Ghostty, Alacritty, Kitty, WezTerm (via
open -na --args) - Linux: all ten terminals
- Windows: Windows Terminal
Shell string (user input shell-quoted):
- macOS: iTerm, Terminal.app (AppleScript has no argv interface)
- Windows: PowerShell, cmd.exe (no argv exec mode)
For shell paths, shellQuote() (POSIX), psQuote() (PowerShell), and cmdQuote() (cmd.exe) are load-bearing — correctness is non-negotiable.
iTerm (lines 266-287):
tell application "iTerm"
if running then
create window with default profile
else
activate
end if
tell current session of current window
write text '<shell-quoted-command>'
end tell
end tellChecks if running first — if already running (even with zero windows), creates new window; if not, activate lets startup open the first.
Terminal (lines 290-300):
tell application "Terminal"
do script '<shell-quoted-command>'
activate
end tellGhostty/Alacritty/Kitty/WezTerm (lines 306-345):
All use pure argv via open -na <App> --args ...:
open -na Ghostty --args --window-save-state=never --working-directory=<cwd> -e <claude> <args...>Each has terminal-specific flags for cwd:
- Ghostty:
--working-directory=<cwd> - Alacritty:
--working-directory <cwd> - Kitty:
--directory <cwd> - WezTerm:
start --cwd <cwd> --
All pure argv. Each terminal has native cwd flags (or spawn({cwd}) for those without):
- gnome-terminal:
--working-directory=<cwd> - konsole:
--workdir <cwd> - kitty:
--directory <cwd> - wezterm:
start --cwd <cwd> -- - alacritty:
--working-directory <cwd> - ghostty:
--working-directory=<cwd> - xfce4/mate:
--working-directory=<cwd> - tilix:
--working-directory=<cwd> - xterm/x-terminal-emulator/generic: spawn({cwd}) — inherit terminal's cwd
Windows Terminal (pure argv):
wt.exe -d <cwd> -- <claude.exe> <args...>PowerShell (shell string):
pwsh.exe -NoExit -Command "Set-Location '<cwd>'; & '<claude>' <arg1> <arg2>..."Uses psQuote() — single-quoted strings with no escape sequences (only '' for literal quote).
cmd.exe (shell string):
cmd.exe /k "cd /d <cwd> && <claude.exe> <args...>"Uses cmdQuote() — strips " characters (can't be safely escaped), doubles % (env var expansion), doubles trailing \ (child process sees backslash before our closing quote).
Bypass for cmd.exe: libuv's default quoting assumes MSVCRT rules. For cmd.exe, set windowsVerbatimArguments: true to skip automatic escaping since our cmdQuote() is already correct.
Spawns terminal detached so handler process exits immediately:
const child = spawn(command, args, {
detached: true, // Allows terminal to outlive handler
stdio: 'ignore', // Don't inherit stdio
cwd: opts.cwd,
windowsVerbatimArguments: opts.windowsVerbatimArguments,
})
child.once('spawn', () => {
child.unref() // Detach completely
resolve(true)
})Resolves false on spawn failure (ENOENT, EACCES) rather than throwing.
Constructs a multi-line warning for deep-link-originated sessions. Always shows the working directory (so user sees which CLAUDE.md will load):
This session was opened by an external deep link in /path/to/project
Optional lines based on context:
- Repo freshness (if
?repo=was used):orResolved owner/repo from local clones · last fetched 2 days agoResolved owner/repo from local clones · last fetched never — CLAUDE.md may be stale - Prompt length (if
?q=was used):or (if >1000 chars)The prompt below was supplied by the link — review carefully before pressing Enter.The prompt below (4521 chars) was supplied by the link — scroll to review the entire prompt before pressing Enter.
Reads .git/FETCH_HEAD mtime to show git freshness:
const gitDir = await getGitDir(cwd)
const commonDir = await getCommonDir(gitDir) // For git worktrees
const [local, common] = await Promise.all([...])
return local > common ? local : common // Whichever is newerFor git worktrees, checks both the worktree's FETCH_HEAD and the main repo's (shared) FETCH_HEAD, returning the newer.
Called fire-and-forget from interactive startup to capture the terminal the user is actually running:
const termProgram = process.env.TERM_PROGRAM // e.g., "iTerm.app", "Apple_Terminal"
const app = TERM_PROGRAM_TO_APP[termProgram.toLowerCase()] // Normalize to app name
saveGlobalConfig(current => ({ ...current, deepLinkTerminal: app }))Stored in global config (per-machine, not synced). The handler's detectMacosTerminal reads this so headless LaunchServices context doesn't lose the user's preference.
DXT (Distribution eXTension) is Claude Code's format for distributing plugins as single-file packages. A DXT file is a ZIP archive containing:
manifest.json— Plugin metadata (author, name, version, MCPs, etc)- Plugin source code, assets, and supporting files
DXT is built on the MCPB (Model Context Protocol Bundle) standard from Anthropic. The system is implemented across two files:
dxt/helpers.ts— Manifest parsing, validation, extension ID generationdxt/zip.ts— ZIP extraction, validation, security scanning
Validates a manifest JSON object against the MCPB schema:
export async function validateManifest(
manifestJson: unknown,
): Promise<McpbManifest>Process:
- Lazy-import
@anthropic-ai/mcpb(deferred to avoid loading ~700KB of zod bound closures at startup) - Use
McpbManifestSchema.safeParse(manifestJson)for validation - On failure, flatten and join all errors into a single message
- Return parsed manifest on success
Why lazy-import? The mcpb package uses zod v3, which eagerly creates 24 .bind(this) closures per schema instance (~300 instances in schemas.js and schemas-loose.js). Deferring keeps ~700KB of bound closures out of the startup heap for sessions that never touch .dxt files.
- Parse JSON from string
- Call validateManifest()
- Throw with context if JSON parsing fails
- Decode bytes as UTF-8
- Call parseAndValidateManifestFromText()
Creates a unique, canonical ID from author and extension name:
function generateExtensionId(
manifest: McpbManifest,
prefix?: 'local.unpacked' | 'local.dxt',
): stringProcess:
- Extract
manifest.author.nameandmanifest.name - Sanitize each:
- Lowercase
- Replace whitespace with
- - Strip non-alphanumeric/dash/underscore/dot
- Collapse multiple dashes
- Strip leading/trailing dashes
- Combine:
{sanitizedAuthor}.{sanitizedName}or{prefix}.{sanitizedAuthor}.{sanitizedName}
Example:
- Author: "Acme Corp", Name: "Code Linter" →
acme-corp.code-linter - With prefix:
local.dxt.acme-corp.code-linter
Consistency: Same algorithm as directory backend for parity across sources (marketplace, local unpacked, DXT archives).
DXT files are ZIP archives, which are notorious for zip bombs (excessive compression, path traversal, symlink attacks). The zip.ts module implements comprehensive validation.
const LIMITS = {
MAX_FILE_SIZE: 512 * 1024 * 1024, // 512MB per file
MAX_TOTAL_SIZE: 1024 * 1024 * 1024, // 1024MB total
MAX_FILE_COUNT: 100000, // File count
MAX_COMPRESSION_RATIO: 50, // Zip bomb ratio
MIN_COMPRESSION_RATIO: 0.5, // Already-compressed content
}Per-file validation called as the filter during unzip:
function validateZipFile(
file: ZipFileMetadata,
state: ZipValidationState,
): FileValidationResultChecks:
- File count: Increment counter, fail if > MAX_FILE_COUNT
- Path safety: Call
isPathSafe(file.name)(prevents traversal/absolute paths) - Individual file size: Fail if > 512MB
- Total uncompressed size: Fail if cumulative > 1024MB
- Compression ratio: Compute
totalUncompressed / compressedSize, fail if > 50:1
Returns { isValid: true } or { isValid: false, error: string }.
Prevents path traversal and absolute paths:
function isPathSafe(filePath: string): boolean {
if (containsPathTraversal(filePath)) return false // Check for ".." segments
const normalized = normalize(filePath) // Resolve "." segments
if (isAbsolute(normalized)) return false // No absolute paths
return true
}Main unzip function with integrated validation:
export async function unzipFile(
zipData: Buffer,
): Promise<Record<string, Uint8Array>>Process:
- Lazy-import fflate (deferred to avoid ~196KB of top-level lookup tables at startup)
- Create validation state (fileCount = 0, totalUncompressedSize = 0, compressedSize = zipData.length)
- Call
unzipSync()with filter function - Filter throws on any validation failure, stopping extraction immediately
- Return record of path → Uint8Array
Why sync? Avoids fflate worker termination crashes in bun (async workers can hang).
Extracts Unix file permissions from ZIP central directory. fflate's unzipSync() returns only data, losing executable bits (everything becomes 0644). This helper reconstructs them for parity with git-clone paths.
Algorithm:
- Find End of Central Directory (EOCD) record (signature 0x06054b50) — scan backwards in trailing ~22 + 65535 bytes
- Read entry count and central directory offset from EOCD
- Walk central directory entries (sig 0x02014b50)
- For each entry:
- Read
versionMadeBy(host OS in high byte) - If high byte === 3 (Unix), extract mode from
externalAttrhigh 16 bits - Store in result map
- Read
- Return map of path → mode
Limitation: Doesn't handle ZIP64 (archives >4GB or >65535 entries), but marketplace DXTs (~3.5MB) and MCPB bundles are tiny.
High-level wrapper that reads file from disk and unzips:
export async function readAndUnzipFile(
filePath: string,
): Promise<Record<string, Uint8Array>>- Read file asynchronously
- Call unzipFile()
- Wrap errors with context (distinguish ENOENT from other errors)
FilePersistence is a system for syncing files created during a Claude Code session back to the Files API (Anthropic's file storage). It's active only in BYOC (Bring Your Own Compute) environments where files are created locally on the user's machine and need to be uploaded to Anthropic's infrastructure.
Lifecycle:
- User starts Claude Code session in BYOC environment
- Session creates files in
{cwd}/{sessionId}/outputs/ - At end of each turn, scanOutputsDirectory finds modified files
- Files are uploaded to Files API via uploadSessionFiles
- File IDs are collected and returned to the turn loop
The system is implemented across two files:
filePersistence/filePersistence.ts— Main orchestration, BYOC vs Cloud branchingfilePersistence/outputsScanner.ts— Directory scanning, mtime-based filtering
Determines deployment mode from CLAUDE_CODE_ENVIRONMENT_KIND:
type EnvironmentKind = 'byoc' | 'anthropic_cloud'- BYOC: User's own infrastructure, needs file upload
- anthropic_cloud (1P): Anthropic's cloud, rclone handles sync (xattr-based file IDs)
Only BYOC mode currently uploads. Cloud mode is a placeholder (lines 247-250) for future xattr-based file ID reading.
Entry point called at end of each turn:
export async function runFilePersistence(
turnStartTime: TurnStartTime,
signal?: AbortSignal,
): Promise<FilesPersistedEventData | null>Arguments:
turnStartTime— Timestamp from turn start (for mtime filtering)signal— AbortSignal for cancellation
Process:
- Check environment: return null if not BYOC
- Get session access token: return null if missing
- Get CLAUDE_CODE_REMOTE_SESSION_ID: log error and return null if missing
- Assemble FilesApiConfig (oauth token, session ID)
- Compute outputsDir:
{cwd}/{sessionId}/outputs/ - Check abort signal: return null if already aborted
- Call executeBYOCPersistence() or executeCloudPersistence()
- Check result: return null if no files and no failures
- Log completion event with success/failure counts and duration
- Return result or throw
Error handling: All errors are caught, logged, and returned as FilesPersistedEventData with empty successes and a single failure entry pointing to outputsDir.
BYOC-specific workflow:
async function executeBYOCPersistence(
turnStartTime: TurnStartTime,
config: FilesApiConfig,
outputsDir: string,
signal?: AbortSignal,
): Promise<FilesPersistedEventData>Algorithm:
- Find modified files via
findModifiedFiles(turnStartTime, outputsDir) - Return empty result if no files
- Check abort signal: return empty if aborted
- Check file count limit: return failure if > FILE_COUNT_LIMIT (1000 files)
- Build file list with relative paths:
filesToProcess = modifiedFiles.map(filePath => ({ path: filePath, relativePath: relative(outputsDir, filePath), }))
- Filter security: skip files where relativePath starts with
..(outside outputs dir) - Call
uploadSessionFiles(filesToProcess, config, DEFAULT_UPLOAD_CONCURRENCY)(concurrency: 10) - Separate results into persistedFiles and failedFiles
- Return summary
Concurrency: 10 concurrent uploads (balanced between throughput and API rate limits).
Wrapper that calls runFilePersistence and emits result via callback:
export async function executeFilePersistence(
turnStartTime: TurnStartTime,
signal: AbortSignal,
onResult: (result: FilesPersistedEventData) => void,
): Promise<void>Catches and logs errors, invokes onResult only if result is non-null.
Scans outputs directory recursively for files modified since turn start:
export async function findModifiedFiles(
turnStartTime: TurnStartTime,
outputsDir: string,
): Promise<string[]>Algorithm:
- Recursively list outputsDir with
fs.readdir(..., { withFileTypes: true, recursive: true }) - Return empty array if directory doesn't exist
- Filter entries:
- Skip symlinks (security)
- Keep regular files only
- Build full paths using parentPath (Node 20+) or fallback
- Parallelize stat calls:
Promise.all(filePaths.map(lstat)) - For each stat result:
- Skip if became symlink between readdir and stat (race condition)
- Keep if
mtimeMs >= turnStartTime
- Return filtered list
Race condition handling: Between readdir and stat, a file might become a symlink. The code detects this and skips.
Concurrency: All stat calls parallelized for efficiency.
type TurnStartTime = number // milliseconds since epochCaptured at turn start so only files modified during the turn are persisted.
type FilesPersistedEventData = {
files: PersistedFile[] // Successfully uploaded files
failed: FailedPersistence[] // Upload failures
}
type PersistedFile = {
filename: string // File path
file_id: string // Files API ID
}
type FailedPersistence = {
filename: string
error: string
}type FilesApiConfig = {
oauthToken: string // Session access token
sessionId: string // CLAUDE_CODE_REMOTE_SESSION_ID
}Checks if file persistence should run:
export function isFilePersistenceEnabled(): boolean {
return feature('FILE_PERSISTENCE') &&
getEnvironmentKind() === 'byoc' &&
!!getSessionIngressAuthToken() &&
!!process.env.CLAUDE_CODE_REMOTE_SESSION_ID
}Gating conditions:
- Feature flag ON (bun:bundle feature)
- Environment is BYOC
- Session access token available
- CLAUDE_CODE_REMOTE_SESSION_ID set
Only public-api/sessions users trigger file persistence, not CLI users.
const OUTPUTS_SUBDIR = 'outputs'
const FILE_COUNT_LIMIT = 1000
const DEFAULT_UPLOAD_CONCURRENCY = 10File persistence runs at the end of each turn:
- Capture
turnStartTime = Date.now()at turn start - Model executes tools, creates files in
outputs/subdirectory - After model finishes, call
executeFilePersistence(turnStartTime, signal, onResult) - Upload runs in background/parallel with other end-of-turn tasks
- Result is collected and reported in turn metadata
Ultraplan:
- Triggered by keyword detection during input processing
- Launches remote session via teleportToRemote()
- Polls remote for approval via pollForApprovedExitPlanMode()
DeepLink:
- Initial session launch (OS calls
--handle-uri) - Detected via CLI flag
--deep-link-origin - Banner shown to user before any interaction
DXT:
- Plugin loading at session init
- Manifest validated during plugin discovery
- ZIP extracted and files cached
FilePersistence:
- Runs at end of each turn (fire-and-forget)
- Parallel with model inference on next turn
- Cancellable via AbortSignal
Logging:
logForDebugging()— All modules use for debug outputlogError()— For errors in main sessionlogEvent()— Analytics events (deepLink registration, ultraplan status, persistence stats)
Path handling:
getCwd()— Get current working directorygetDisplayPath()— Shorten paths for UI- Git utilities — For repo detection, last fetch time
Error handling:
errorMessage()— Normalize error objects to stringsisENOENT()— Distinguish file-not-found from other errors- Error types with context throughout
Configuration:
getGlobalConfig()/saveGlobalConfig()— Per-machine config (deeplink terminal preference)getInitialSettings()— User settings (disableDeepLinkRegistration flag)
DeepLink → Shell:
- Shell quoting (shellQuote, psQuote, cmdQuote) is load-bearing
- Pure argv paths preferred (no shell interpretation)
- Control character filtering on input
DXT → ZIP extraction:
- Path traversal prevention (no "..", no absolute paths)
- File size limits (per-file, total, compression ratio)
- Symlink skipping (don't follow)
FilePersistence → Output directory:
- Only scan outputs/ subdirectory
- Skip symlinks
- Check relativePath doesn't escape via ".."
Ultraplan → Plan extraction:
- Sentinel marker check (prevents executing wrong text)
- Marker presence validation (throws if missing)
| Flag | Module | Purpose |
|---|---|---|
tengu_lodestone_enabled |
DeepLink | Enable deep link protocol registration |
FILE_PERSISTENCE |
FilePersistence | Enable file upload system |
| Variable | Module | Purpose |
|---|---|---|
CLAUDE_CODE_ENVIRONMENT_KIND |
FilePersistence | BYOC vs Cloud mode |
CLAUDE_CODE_REMOTE_SESSION_ID |
FilePersistence, others | Remote session ID |
TERM_PROGRAM |
DeepLink | Terminal detection hint |
__CFBundleIdentifier |
DeepLink | macOS URL launch detection |
| Path | Module | Purpose |
|---|---|---|
~/.claude/config.json |
DeepLink | Global config (per-machine, terminal preference) |
~/.claude.json |
Settings | User settings (synced, disableDeepLinkRegistration) |
MCPB manifest validation (dxt/helpers.ts):
- Deferred import of
@anthropic-ai/mcpb - Saves ~700KB startup cost for non-plugin sessions
fflate zip extraction (dxt/zip.ts):
- Deferred import of
fflate - Saves ~196KB startup cost for non-DXT sessions
File persistence uploads (filePersistence.ts):
- 10 concurrent uploads (DEFAULT_UPLOAD_CONCURRENCY)
- Parallelized stat calls during directory scan
Terminal detection (terminalLauncher.ts):
- macOS mdfind and /Applications checks run in parallel
- Linux terminal check uses which() sequentially (short list)
Ultraplan polling (ultraplan/ccrSession.ts):
- 3-second interval (POLL_INTERVAL_MS)
- Paginated events (up to 50 pages per call)
- Backoff on transient failures (max 5 consecutive)
| Module | Error Types | Handling |
|---|---|---|
| Ultraplan | UltraplanPollError | Structured failures, rejectCount tracking |
| DeepLink | URI parsing errors | Throw with context, exit code 1 |
| DXT | Manifest validation | Throw with error details |
| FilePersistence | Upload failures | Collect as FailedPersistence, continue |
- Transient (retry): Network errors, temporary ENOENT
- Permanent (give up, log, backoff): EACCES, ENOSPC (permissions), invalid input, validation failures
| Threat | Mitigation |
|---|---|
| Prompt injection via deep link | Control char filtering, long-prompt warning |
| Path traversal in DXT | isPathSafe check, ".." rejection, normalization |
| Zip bomb | Compression ratio limit (50:1), file size limits |
| Command injection via shell | Shell-specific quoting (shellQuote, psQuote, cmdQuote) |
| Symlink attacks | Symlink skipping in ZIP extraction and file scanning |
| Stale CLAUDE.md | Git freshness check (FETCH_HEAD mtime) |
- Shell quoting functions: cmdQuote, psQuote, shellQuote (correctness is non-negotiable)
- Path safety check: isPathSafe (prevents directory traversal)
- Zip validation filter: validateZipFile (runs during extraction, can stop immediately)
- Marker extraction: extractApprovedPlan (throws if marker missing, prevents wrong plan execution)
Ultraplan:
- Scanner state machine (pending → approved, pending → rejected → pending → approved)
- Marker extraction (with and without edits, missing marker error)
- Phase transitions (running → needs_input → running)
DeepLink:
- URI parsing (valid/invalid URIs, control char rejection, max length enforcement)
- Shell quoting (spaces, quotes, metacharacters in paths/queries)
- Terminal detection (mock TERM_PROGRAM, check priority order)
DXT:
- Manifest validation (valid/invalid schemas, error flattening)
- Extension ID generation (sanitization, prefix handling)
- ZIP security (zip bomb detection, path traversal rejection, compression ratio check)
FilePersistence:
- File discovery (mtime filtering, symlink skipping, race condition handling)
- Upload concurrency (parallelization correctness)
- Security (relativePath escape detection)
- Full deep link flow (parse → register → detect terminal → launch)
- Ultraplan poll loop (event batches, phase changes, timeout scenarios)
- DXT extraction (large archives, edge cases like nested symlinks)
- File persistence (scan → upload → collection in BYOC mode)
These four utility subsystems represent sophisticated engineering addressing non-trivial problems:
- Ultraplan solves multi-step planning in a distributed system with polling, rejection handling, and lifecycle tracking
- DeepLink bridges OS-level URI schemes to terminal launch across three platforms with security warnings and terminal preference persistence
- DXT implements secure plugin distribution with comprehensive zip bomb detection and path traversal prevention
- FilePersistence synchronizes files from BYOC to cloud infrastructure with concurrent uploads and abort signal support
All four prioritize security (input validation, shell escaping, path safety) and performance (lazy imports, concurrency, efficient scanning). They integrate seamlessly with the main session loop via feature flags, environment variables, and callbacks.