zCode CLI X — Service Architecture Map
Generated: May 5, 2026
Context: Wiring services into the Telegram bot
Architecture Overview
Two distinct layers coexist:
- Custom JS shim (
src/zcode.js → bin/zcode.js) — the simplified entry point that the Telegram bot uses. Clean, independent initialization chain.
- Original TypeScript codebase (Claude Code fork:
src/main.tsx, src/entrypoints/cli.tsx) — rich service layer used by the CLI. Most services live here but are NOT wired into the JS shim.
The JS shim (zcode.js) is what runs in production. The TS codebase is available as a library but is not connected to the bot.
PART 1: Custom JS Layer (Currently Wired)
Initialization Chain in src/zcode.js
1.1 src/zcode.js
| Field |
Value |
| Path |
src/zcode.js |
| Exported API |
async function zcode(options) |
| Init |
Called from bin/zcode.js via import { zcode } from '../src/zcode.js' |
| Options |
{ bot: boolean, cli: boolean } |
| Notes |
Passes config, api, tools, skills to initBot(). Does NOT pass agents. |
1.2 src/utils/env.js
| Field |
Value |
| Path |
src/utils/env.js |
| Exported API |
function checkEnv() |
| Returns |
{ valid, missing, ZAI_API_KEY, GLM_BASE_URL, TELEGRAM_BOT_TOKEN, TELEGRAM_ALLOWED_USERS } |
| Init |
checkEnv() — no constructor, stateless |
| Required vars |
ZAI_API_KEY, GLM_BASE_URL |
1.3 src/config/index.js
| Field |
Value |
| Path |
src/config/index.js |
| Exported API |
async function initConfig() |
| Returns |
Config object: { api, telegram, tools, skills, agents, logging } |
| Init |
const config = await initConfig() |
| Config source |
.zcode.config.json in CWD (auto-created from defaults if absent) |
1.4 src/api/index.js
| Field |
Value |
| Path |
src/api/index.js |
| Exported API |
async function initAPI() — returns { config, client } |
|
class ZAIProvider — constructor(api), chat(messages, opts), complete(prompt, opts) |
|
function createZAIProvider(api) — factory |
| Init |
const api = await initAPI() connects to Z.AI and tests /models endpoint |
| Notes |
ZAIProvider uses api.client (axios). chat() POSTs to /chat/completions. |
| Provider class usage |
new ZAIProvider(api).chat([{role:'user', content: text}], {model:'glm-5.1'}) |
1.5 src/tools/index.js
| Field |
Value |
| Path |
src/tools/index.js |
| Exported API |
async function initTools() — returns tools[] |
|
class BashTool — .execute(command, options) |
|
class FileEditTool — .read(path), .write(path, content), .append(path, content), .edit(path, oldText, newText) |
|
class WebSearchTool — .search(query, options) |
|
class GitTool — .status(), .log(options), .diff(options), .commit(message), .push(), .pull() |
| Init |
const tools = await initTools() — instantiates each tool class, filtered by env flags |
| Env flags |
ZCODE_ENABLE_BASH, ZCODE_ENABLE_FILE_EDIT, ZCODE_ENABLE_WEB_SEARCH, ZCODE_ENABLE_GIT |
1.6 src/skills/index.js
| Field |
Value |
| Path |
src/skills/index.js |
| Exported API |
async function initSkills() — returns skills[] of { name, description, version, category } |
| Init |
const skills = await initSkills() |
| Sources |
(1) .json/.js files in skills/ dir in CWD, (2) 5 built-in skills hardcoded |
| Built-in skills |
code_review, bug_fix, refactor, documentation, testing |
1.7 src/agents/index.js
| Field |
Value |
| Path |
src/agents/index.js |
| Exported API |
async function initAgents() — returns agents[] of { id, name, description, capabilities, enabled } |
|
class AgentOrchestrator — constructor(agents), execute(agentId, task, context), getAgent(id), listAgents() |
| Init |
const agents = await initAgents() |
| Built-in agents |
coder, architect, devops (all enabled by default) |
1.8 src/bot/index.js
| Field |
Value |
| Path |
src/bot/index.js |
| Exported API |
async function initBot(config, api, tools, skills) — returns { send, ws, waitForMessages, getConnections } |
| Init |
const bot = await import('./bot/index.js').then(m => m.initBot(config, api, tools, skills)) |
| Current state |
THIN: creates Express+WebSocket server, handles webhook POSTs, routes messages through ZAIProvider directly. Does NOT use tools/skills/agents params. |
| Return value |
{ send: sendTelegramMessage(chatId, text, opts), ws: sendWebSocketMessage(chatId, msg), waitForMessages: async (), getConnections: () => num } |
1.9 src/utils/logger.js
| Field |
Value |
| Path |
src/utils/logger.js |
| Exported API |
export const logger — winston logger instance |
| Init |
Import and use directly: import { logger } from '../utils/logger.js' |
| Features |
Console transport (colorized), optional file transport via LOG_FILE env var |
1.10 src/utils/rtk.js
| Field |
Value |
| Path |
src/utils/rtk.js |
| Exported API |
class RTKIntegration — init(), isCommandSupported(cmd), optimizeCommand(command, args), getTrackingStats(), listSupportedCommands() |
|
function getRTK() — singleton factory |
| Init |
const rtk = getRTK(); await rtk.init() |
| Status |
Singleton. Lazily instantiated. Used by BashTool and GitTool. |
PART 2: Original TypeScript Service Layer (Available but NOT wired into bot)
These services exist in the Claude Code fork but are not imported or used by the JS shim (zcode.js → bot/index.js). They can be imported directly if needed.
2.1 Voice Service
| Field |
Value |
| Path |
src/services/voice.ts |
| Exported API |
startRecording(fallbackToSoX?), stopRecording(), checkRecordingAvailability() (need full export list) |
| Init |
import { startRecording, stopRecording } from '../services/voice.ts' — no init, module-level state |
| Dependencies |
audio-capture-napi (native), falls back to SoX/arecord on Linux |
2.2 Cron Scheduler
| Field |
Value |
| Path |
src/utils/cronScheduler.ts |
| Exported API |
class CronScheduler with options { onFire, isLoading, assistantMode }, start(), stop() |
|
isRecurringTaskAged(t, nowMs, maxAgeMs) |
|
getSchedulerCheckDelayMs(nextFireAtMs, nowMs, options) |
| Init |
Needs cronTasks.ts utilities: readCronTasks, findMissedTasks, markCronTasksFired |
| Dependencies |
cronTasks.ts, cronTasksLock.ts, cron.ts, bootstrap/state.ts |
2.3 MCP Validation
| Field |
Value |
| Path |
src/utils/mcpValidation.ts |
| Exported API |
getMaxMcpOutputTokens(), getContentSizeEstimate(content), MCPToolResult type |
|
Internal: truncateContentBlocks(blocks, maxChars), truncateString(content, maxChars) |
| Init |
Import functions directly |
| Dependencies |
Anthropic SDK types, imageResizer.ts, tokenEstimation.ts |
2.4 Memory System
| Field |
Value |
| Path |
src/utils/memoryFileDetection.ts |
|
src/memdir/memoryTypes.ts |
|
src/memdir/memoryScan.ts |
|
src/memdir/memoryAge.ts |
| Exported API (memoryTypes.ts) |
MEMORY_TYPES (['user', 'feedback', 'project', 'reference']), parseMemoryType(raw) |
|
TYPES_SECTION_COMBINED (system prompt text), TYPES_SECTION_PRIVATE |
2.5 Context Compression (Compact)
| Field |
Value |
| Path |
src/services/compact/compact.ts (1706 lines) |
|
src/services/compact/cachedMicrocompact.ts |
|
src/services/compact/apiMicrocompact.ts |
|
src/services/compact/compactWarningState.ts |
| Init |
Deeply integrated into the main loop (main.tsx/query.ts). Not standalone. |
2.6 Tool Orchestration
| Field |
Value |
| Path |
src/services/tools/toolOrchestration.ts |
| Exported API |
runTools(toolUseMessages, assistantMessages, canUseTool, toolUseContext) — async generator |
|
DEFAULT_MAX_TOOL_USE_CONCURRENCY, getMaxToolUseConcurrency() |
| Dependencies |
toolExecution.ts, toolConcurrency.ts, StreamingToolExecutor.ts, toolHooks.ts |
2.7 Team Memory Sync
| Field |
Value |
| Path |
src/services/teamMemorySync/index.ts |
| Exported API |
Sync service for team memory files between local FS and server API |
| Dependencies |
Axios, OAuth, git remote, secret scanner |
2.8 Other Services (brief)
| Service |
Path |
Purpose |
| Notifier |
src/services/notifier.ts |
sendNotification(opts, terminal) — desktop notifications |
| Prevent Sleep |
src/services/preventSleep.ts |
startPreventSleep(), stopPreventSleep(), forceStopPreventSleep() — macOS caffeinate |
| Token Estimation |
src/services/tokenEstimation.ts |
Token counting with Anthropic/Bedrock/Vertex APIs |
| Rate Limit Messages |
src/services/rateLimitMessages.ts |
getRateLimitMessage(limits, model), isRateLimitErrorMessage(text) |
| VCR |
src/services/vcr.ts |
Fixture caching for tests (withVCR) |
| MCP Services |
src/services/mcp/ |
VSCode SDK MCP, connection management, normalization, headers |
| OAuth |
src/services/oauth/ |
OAuth client, crypto, profile, auth-code listener |
| Analytics |
src/services/analytics/ |
Event logging and feature flags (GrowthBook/Statsig) |
| Scheduled Tasks |
src/utils/cronTasks.ts |
CronTask type, readCronTasks(), findMissedTasks() |
| Model Providers |
src/utils/model/providers.ts |
APIProvider type, getAPIProvider(), provider detection |
PART 3: Missing Wire-Up in Current Bot
The current bot/index.js receives config, api, tools, skills but only uses api (via ZAIProvider). Specifically:
| Parameter |
Passed by zcode.js? |
Used by bot/index.js? |
config |
✅ |
❌ (not referenced) |
api |
✅ |
✅ (used for ZAIProvider) |
tools |
✅ |
❌ (not referenced) |
skills |
✅ |
❌ (not referenced) |
agents |
❌ (not passed) |
❌ (not available) |
Telegram Bot Options (TS — not wired)
Two additional Telegram implementations exist but are not connected:
src/telegram-bot.ts — class TelegramBot with startPolling(), sendMessage(), sendMarkdown() — spawns zcode as subprocess
src/telegram-bot-cli.ts — CLI entrypoint that loads config from .env and runs TelegramBot.startPolling()
These are standalone and do NOT use the service architecture.
PART 4: Entry Points
| Entry Point |
Path |
Description |
| CLI (production) |
bin/zcode.js |
Runs zcode() from src/zcode.js. Commander-based CLI, loads dotenv. |
| CLI (TS fork) |
src/entrypoints/cli.tsx |
Full Claude Code fork CLI (Bun-bundled to dist/cli.mjs) |
| Init |
src/entrypoints/init.ts |
Project initialization |
| MCP Server |
src/entrypoints/mcp.ts |
MCP server entrypoint |
| SDK |
src/entrypoints/sdk/ |
Agent SDK entrypoints |
PART 5: How to Wire a Service Into the Telegram Bot
Pattern (from src/zcode.js):
To use TS services from the JS bot — use dynamic import():
For singleton services (like RTK), use the singleton factory pattern already established: