InkdownInkdown
Start writing

Claude-Code

62 files·4 subfolders

Shared Workspace

Claude-Code
codex

08-services

Shared from "Claude-Code" on Inkdown

Services Architecture

Overview

The Services layer handles all external integrations - APIs, authentication, analytics, and third-party protocols. This is where Claude Code talks to the outside world.

Plain text
┌─────────────────────────────────────────────────────────────────────────────┐
│                        SERVICES ARCHITECTURE                                 │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │                       CORE SERVICES                                  │   │
│  │                                                                       │   │
│  │  ┌────────────┐  ┌────────────┐  ┌────────────┐  ┌────────────┐        │   │
│  │  │   Anthropic │  │  GrowthBook│  │   OAuth   │  │   Policy   │        │   │
│  │  │    API      │  │ (Features) │  │   Auth    │  │   Limits   │        │   │
│  │  │  (Claude)   │  │            │  │           │  │            │        │   │
│  │  └────────────┘  └────────────┘  └────────────┘  └────────────┘        │   │
│  │                                                                       │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│                                                                             │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │                     PROTOCOL SERVICES                                │   │
│  │                                                                       │   │
│  │  ┌────────────┐  ┌────────────┐  ┌────────────┐  ┌────────────┐        │   │
│  │  │    MCP     │  │    LSP     │  │   OAuth   │  │   VCR     │        │   │
│  │  │ (Servers)  │  │(Lang Svcs) │  │  Servers  │  │ (Replay)  │        │   │
│  │  └────────────┘  └────────────┘  └────────────┘  └────────────┘        │   │
│  │                                                                       │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│                                                                             │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │                    INFRASTRUCTURE SERVICES                           │   │
│  │                                                                       │   │
│  │  ┌────────────┐  ┌────────────┐  ┌────────────┐  ┌────────────┐        │   │
│  │  │  Analytics │  │   Files    │  │  Settings │  │   Remote   │        │   │
│  │  │  (PostHog) │  │    API     │  │   Sync    │  │ Settings   │        │   │
│  │  └────────────┘  └────────────┘  └────────────┘  └────────────┘        │   │
│  │                                                                       │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘
0000_start_here_index_and_recommended_reading_order.md
0100_project_overview_tech_stack_runtime_modes_and_folder_map.md
0200_startup_flow_entry_points_and_cold_start_sequence.md
0300_codebase_modules_layers_state_models_and_schemas.md
0400_system_architecture_and_design_rationale.md
0500_interactive_repl_request_flow_end_to_end.md
0600_headless_sdk_and_print_mode_request_flow_end_to_end.md
0700_mcp_integration_connection_and_tool_call_flow.md
0800_external_services_sdks_storage_and_local_dependencies.md
0900_environment_variables_settings_feature_flags_and_failure_modes.md
1000_non_obvious_patterns_gotchas_and_debugging_traps.md
1100_full_codebase_file_inventory_grouped_by_directory.md
kimi
00-overview.md
01-entrypoints.md
02-state-management.md
03-query-system.md
04-tools-system.md
05-tasks-system.md
06-ui-components.md
07-bridge-remote.md
08-services.md
09-skills-plugins.md
10-commands.md
11-testing-architecture.md
12-permission-system.md
13-build-system.md
14-ink-internals.md
15-git-internals.md
16-context-compaction.md
17-vim-mode.md
18-mailbox-notifications.md
19-session-persistence.md
20-hooks-system.md
21-error-recovery.md
README.md
qwen
00-overview.md
01-entry-points.md
02-query-engine.md
03-tools-and-tasks.md
04-commands-and-skills.md
05-state-management.md
06-ink-rendering.md
07-bridge-remote.md
08-mcp-services.md
09-services-overview.md
10-multi-agent.md
11-system-prompt-constants.md
12-tool-interface.md
13-memory-system.md
14-buddy-companion.md
15-keybindings.md
16-stop-hooks.md
17-vim-mode.md
18-upstreamproxy.md
19-cost-tracking-history.md
20-contexts-styles-onboarding.md
21-hooks.md
22-screens.md
tweets-explain
claude-code-memory-analysis.md
compact
memory-system
agentic-architecture

Core Services

Anthropic API Service

File: services/api/claude.ts

TypeScript
// Core API wrapper
export async function streamMessages(
  config: APIConfig
): Promise<Stream<RawMessageStreamEvent>> {
  const client = getAnthropicClient()

  return await client.messages.create({
    model: config.model,
    max_tokens: config.max_tokens,
    system: config.system,
    messages: config.messages,
    tools: config.tools,
    stream: true,
    // Beta features
    thinking: config.thinking,
    task_budget: config.taskBudget,
  })
}
Key Features
FeatureDescription
StreamingReal-time token streaming
Retry LogicExponential backoff on failures
Rate LimitingHandles 429s gracefully
Error CategorizationClassifies retryable vs fatal errors
Token TrackingReal-time usage monitoring
Error Handling
TypeScript
// services/api/errors.ts
export function categorizeRetryableAPIError(error: APIError): ErrorCategory {
  switch (error.status) {
    case 429:
      return {
        type: 'rate_limit',
        retryable: true,
        delayMs: parseRetryAfter(error),
      }
    case 500:
    case 502:
    case 503:
      return {
        type: 'server_error',
        retryable: true,
        delayMs: 1000 * (2 ** attemptCount),  // Exponential backoff
      }
    case 413:
    case 'prompt_too_long':
      return {
        type: 'context_length',
        retryable: false,  // Needs compaction
      }
    default:
      return { type: 'unknown', retryable: false }
  }
}

GrowthBook (Feature Flags)

File: services/analytics/growthbook.ts

TypeScript
// Initialize feature flags
export async function initializeGrowthBook(): Promise<void> {
  const gb = new GrowthBook({
    apiHost: 'https://cdn.growthbook.io',
    clientKey: GROWTHBOOK_CLIENT_KEY,
    attributes: {
      id: getUserId(),
      version: MACRO.VERSION,
      platform: getPlatform(),
    },
  })

  await gb.init()
  setGlobalInstance(gb)
}

// Check feature
export function isFeatureEnabled(featureKey: string): boolean {
  return getGrowthBook().isOn(featureKey)
}

// Build-time dead code elimination
export function feature(featureKey: string): boolean {
  // This is a macro replaced at build time
  return MACRO.FEATURES[featureKey] ?? false
}
Feature Flag Types
TypeDescriptionExample
Build-timeDead code eliminationfeature('BRIDGE_MODE')
RuntimeDynamic enablementisFeatureEnabled('new_ui')
UserPer-user gatesisClaudeAISubscriber()

OAuth & Authentication

File: services/oauth/index.ts

TypeScript
// OAuth flow for claude.ai integration
export async function startOAuthFlow(
  provider: 'claude-ai' | 'github' | 'slack'
): Promise<AuthResult> {
  // 1. Generate PKCE challenge
  const { codeChallenge, codeVerifier } = generatePKCE()

  // 2. Open browser for auth
  const authUrl = buildAuthUrl({
    clientId: getClientId(provider),
    redirectUri: 'http://localhost:3000/callback',
    codeChallenge,
  })

  await openBrowser(authUrl)

  // 3. Start local server for callback
  const code = await waitForCallback()

  // 4. Exchange code for tokens
  const tokens = await exchangeCode(code, codeVerifier)

  // 5. Store securely
  await saveSecurely(`oauth-${provider}`, tokens)

  return { success: true }
}
Secure Storage
TypeScript
// utils/secureStorage/index.ts
export async function saveSecurely(
  key: string,
  value: string
): Promise<void> {
  if (isMacOS()) {
    // macOS Keychain
    await setInKeychain(key, value)
  } else if (isWindows()) {
    // Windows Credential Manager
    await setWindowsCredential(key, value)
  } else {
    // Linux: Secret Service API
    await setSecretService(key, value)
  }
}

Policy Limits

File: services/policyLimits/index.ts

Enterprise policy enforcement:

TypeScript
export type PolicyLimits = {
  // Feature allowlisting
  allow_remote_control: boolean
  allow_mcp_servers: boolean
  allow_auto_mode: boolean

  // Rate limits
  max_requests_per_hour: number
  max_tokens_per_day: number

  // Data exfiltration
  blocked_domains: string[]
  allowed_git_orgs: string[]
}

export function isPolicyAllowed(feature: keyof PolicyLimits): boolean {
  const limits = getLoadedPolicyLimits()
  return limits[feature] ?? true  // Default allow
}

Protocol Services

MCP (Model Context Protocol)

File: services/mcp/client.ts

TypeScript
// MCP server connection
export async function connectMcpServer(
  config: McpServerConfig
): Promise<MCPServerConnection> {
  const transport = new StdioClientTransport({
    command: config.command,
    args: config.args,
    env: config.env,
  })

  const client = new Client({ name: 'claude-code', version: '1.0' })
  await client.connect(transport)

  // Discover capabilities
  const { tools, resources } = await Promise.all([
    client.listTools(),
    client.listResources(),
  ])

  return {
    name: config.name,
    client,
    tools: tools.map(convertMcpTool),
    resources,
    status: 'connected',
  }
}
MCP Architecture
Plain text
┌─────────────────────────────────────────────────────────────────┐
│                    MCP ARCHITECTURE                              │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  ┌─────────────────┐                                            │
│  │   CLAUDE CODE   │                                            │
│  │                 │                                            │
│  │  ┌───────────┐  │                                            │
│  │  │   MCP     │  │    stdio /    ┌──────────────────┐          │
│  │  │  Client   │◄─┼─────HTTP─────►│   MCP Server     │          │
│  │  └───────────┘  │    / SSE      │  (External)      │          │
│  └─────────────────┘               │                  │          │
│                                     │  ┌───────────┐  │          │
│                                     │  │   Tools   │  │          │
│                                     │  │ Resources │  │          │
│                                     │  └───────────┘  │          │
│                                     └──────────────────┘          │
│                                                                 │
│  Example servers:                                               │
│  - @anthropic/mcp-postgres (database)                           │
│  - @anthropic/mcp-github (GitHub API)                           │
│  - @modelcontextprotocol/server-puppeteer (browser)             │
│  - Custom internal servers                                      │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘
LSP (Language Server Protocol)

File: services/lsp/manager.ts

TypeScript
// LSP client management
export class LspServerManager {
  private servers = new Map<string, LspConnection>()

  async connect(languageId: string, rootPath: string): Promise<LspConnection> {
    const serverPath = getLspPath(languageId)

    const connection = createConnection(serverPath, rootPath)
    await connection.initialize({
      rootPath,
      capabilities: CLIENT_CAPABILITIES,
    })

    this.servers.set(rootPath, connection)
    return connection
  }

  async getCompletions(
    filePath: string,
    position: Position
  ): Promise<CompletionItem[]> {
    const connection = this.getConnectionForFile(filePath)
    return await connection.completion({ textDocument: { uri: filePath }, position })
  }
}

Infrastructure Services

Analytics (PostHog)

File: services/analytics/index.ts

TypeScript
// Event tracking
export function logEvent(
  eventName: string,
  properties?: Record<string, unknown>
): void {
  const posthog = getPostHogClient()

  posthog.capture({
    distinctId: getUserId(),
    event: eventName,
    properties: {
      ...properties,
      $session_id: getSessionId(),
      version: MACRO.VERSION,
    },
  })
}

// Usage in code
logEvent('tool_invoked', {
  tool_name: 'BashTool',
  duration_ms: 500,
})
Privacy
  • No file contents sent
  • No user code sent
  • Only metadata (tool names, durations, counts)
  • Opt-out available in settings
Files API

File: services/api/filesApi.ts

TypeScript
// Upload files for attachment
export async function uploadFile(
  filePath: string,
  config: FilesApiConfig
): Promise<UploadResult> {
  const stream = createReadStream(filePath)

  const response = await fetch(config.uploadUrl, {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${config.token}`,
      'Content-Type': 'application/octet-stream',
    },
    body: stream,
    duplex: 'half',
  })

  return { fileId: response.headers.get('X-File-Id') }
}

// Download session files
export async function downloadSessionFiles(
  specs: FileSpec[],
  config: FilesApiConfig
): Promise<DownloadResult> {
  // Parallel downloads with progress
  const downloads = specs.map(spec => downloadSingle(spec, config))
  return await Promise.all(downloads)
}
Settings Sync

File: services/settingsSync/index.ts

TypeScript
// Sync settings across devices
export async function syncSettings(): Promise<void> {
  const localSettings = loadLocalSettings()
  const remoteSettings = await fetchRemoteSettings()

  // Merge with timestamps
  const merged = mergeSettings(localSettings, remoteSettings)

  // Save locally
  saveLocalSettings(merged)

  // Push if local was newer
  if (hasLocalChanges(localSettings, merged)) {
    await pushSettings(merged)
  }
}

Service Initialization Order

Plain text
┌─────────────────────────────────────────────────────────────────┐
│                  SERVICE INIT ORDER                              │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  Phase 1: Bootstrap (cli.tsx)                                     │
│  ─────────────────────────────────                               │
│  1. Profile checkpoint                                          │
│  2. Fast-path routing                                             │
│                                                                 │
│  Phase 2: Core Init (main.tsx)                                    │
│  ─────────────────────────────────                               │
│  3. Auth (keychain prefetch)                                     │
│  4. Config loading                                                │
│  5. GrowthBook (feature flags)                                   │
│  6. Policy limits                                                 │
│                                                                 │
│  Phase 3: Network Services                                        │
│  ─────────────────────────────────                               │
│  7. Telemetry sinks                                               │
│  8. Analytics (PostHog)                                           │
│  9. MCP connections                                               │
│  10. LSP servers (lazy)                                          │
│                                                                 │
│  Phase 4: UI Launch                                               │
│  ─────────────────────────────────                               │
│  11. React mount                                                  │
│  12. REPL render                                                  │
│                                                                 │
│  Phase 5: Background                                              │
│  ─────────────────────────────────                               │
│  13. Settings sync                                                │
│  14. Auto-updater check                                           │
│  15. Plugin loading                                               │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

Service Configuration

Environment Variables
Bash
# API Configuration
ANTHROPIC_API_KEY=sk-ant-...
ANTHROPIC_BASE_URL=https://api.anthropic.com

# Feature Flags
CLAUDE_CODE_GROWTHBOOK_KEY=...

# OAuth
CLAUDE_CODE_CLIENT_ID=...

# MCP
CLAUDE_CODE_MCP_CONFIG_PATH=~/.claude/mcp.json

# Analytics Opt-out
CLAUDE_CODE_DISABLE_ANALYTICS=1

# Remote Settings
CLAUDE_CODE_REMOTE_SETTINGS_URL=...
Config Files
JSON
// ~/.claude/mcp.json
{
  "mcpServers": {
    "postgres": {
      "command": "npx",
      "args": ["-y", "@anthropic/mcp-postgres"],
      "env": {
        "DATABASE_URL": "postgres://..."
      }
    },
    "github": {
      "command": "npx",
      "args": ["-y", "@anthropic/mcp-github"],
      "env": {
        "GITHUB_TOKEN": "ghp_..."
      }
    }
  }
}

Error Handling

Service Error Categories
CategoryExamplesHandling
NetworkTimeout, DNS failureRetry with backoff
Auth401, token expiredRe-auth prompt
Rate Limit429, quota exceededWait + retry
Server500, 503Retry limited times
Client400, 404Log and continue
Retry Decorator
TypeScript
// utils/retry.ts
export function withRetry<T>(
  fn: () => Promise<T>,
  options: RetryOptions
): Promise<T> {
  const { maxAttempts, backoffMs } = options

  return async function attempt(n: number): Promise<T> {
    try {
      return await fn()
    } catch (error) {
      if (n >= maxAttempts || !isRetryable(error)) {
        throw error
      }

      await sleep(backoffMs * (2 ** n))
      return attempt(n + 1)
    }
  }(0)
}

Testing Services

Mock Pattern
TypeScript
// tests/mocks/services.ts
export function mockAnthropicAPI(): MockAPI {
  return {
    streamMessages: jest.fn(async function* () {
      yield { type: 'text', text: 'Mock response' }
    }),
  }
}

export function mockGrowthBook(features: Record<string, boolean>): MockGrowthBook {
  return {
    isOn: (key: string) => features[key] ?? false,
  }
}
VCR Recording

File: services/vcr.ts

Records and replays API interactions for tests:

TypeScript
// Record mode
withVCR('test-name', async () => {
  // API calls recorded to fixtures/test-name.json
  const result = await streamMessages(config)
})

// Replay mode
withVCR('test-name', async () => {
  // Returns recorded responses, no actual API call
})

Key Concepts

1. Lazy Initialization

Services start only when needed. LSP servers connect on first file open.

2. Graceful Degradation

If a service fails (e.g., analytics), the app continues.

3. Retry Everything

Network is unreliable. All external calls retry with backoff.

4. Privacy First

No sensitive data in analytics. Local processing preferred.

5. Feature Gating

Services check GrowthBook before initializing (e.g., bridge mode).


Related Documentation

  • Entrypoints - Service initialization
  • Query System - API service usage
  • Bridge & Remote - Bridge services