Skip to content

Architecture

This page describes how xopc is structured and how the main pieces fit together.

System Architecture

┌─────────────────────────────────────────────────────────────┐
│                      xopc                                │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  ┌─────────────────────────────────────────────────────┐   │
│  │                    CLI Layer                         │   │
│  │  ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐   │   │
│  │  │ setup   │ │ onboard │ │ agent   │ │ gateway │   │   │
│  │  └─────────┘ └─────────┘ └─────────┘ └─────────┘   │   │
│  └─────────────────────────────────────────────────────┘   │
│                            │                                │
│  ┌─────────────────────────────────────────────────────┐   │
│  │                     Core                             │   │
│  │  ┌─────────────────────────────────────────────┐   │   │
│  │  │              AgentService                    │   │   │
│  │  │  ┌─────────┐ ┌─────────┐ ┌─────────┐       │   │   │
│  │  │  │ Prompt  │ │ Memory  │ │ Skills  │       │   │   │
│  │  │  │ Builder │ │ Search  │ │         │       │   │   │
│  │  │  └─────────┘ └─────────┘ └─────────┘       │   │   │
│  │  └─────────────────────────────────────────────┘   │   │
│  └─────────────────────────────────────────────────────┘   │
│                            │                                │
│  ┌─────────────────────────────────────────────────────┐   │
│  │                   Providers                          │   │
│  │            @mariozechner/pi-ai (20+ providers)      │   │
│  └─────────────────────────────────────────────────────┘   │
│                            │                                │
└────────────────────────────┼────────────────────────────────┘

        ┌────────────────────┼────────────────────┐
        │                    │                    │
        ▼                    ▼                    ▼
  ┌──────────┐        ┌──────────┐        ┌──────────┐
  │ Telegram │        │   Cron   │        │ Gateway  │
  │ Channel  │        │ Scheduler│        │   API    │
  └──────────┘        └──────────┘        └──────────┘

Project Structure

src/
├── agent/              # Core agent logic (pi-agent-core based)
│   ├── service.ts      #   Main AgentService class
│   ├── memory/         #   Curated store, MemoryManager, prefetch; session transcripts live under session/
│   ├── prompt/         #   Prompt builder system
│   ├── tools/          #   Built-in tools (Typebox schemas)
│   └── progress.ts     #   Progress feedback system
├── infra/
│   └── bus/            # Message bus primitives (queue, etc.)
├── channels/           # Channel integrations (ChannelPlugin + manager)
│   ├── plugin-types.ts #   ChannelPlugin interface & adapters
│   ├── manager.ts      #   Channel lifecycle manager
│   ├── plugins/
│   │   ├── bundled.ts  #   Built-in workspace plugins (Telegram)
│   │   ├── registry.ts #   Plugin registry / lookup
│   │   └── types.*.ts  #   Registry type helpers
│   ├── telegram/
│   │   └── index.ts    #   Re-exports from @xopcai/xopc-extension-telegram (compat)
│   ├── outbound/       #   Outbound delivery pipeline
│   ├── security.ts     #   Access control helpers
│   ├── draft-stream.ts #   Streaming message preview
│   └── format.ts       #   Markdown to HTML formatter
├── extensions/         # Extension runtime (loader, hooks); `sdk/` → @xopcai/xopc/extension-sdk
├── routing/            # Session keys, bindings, route resolution
├── acp/                # Agent Control Protocol (optional multi-runtime bridge)
├── cli/                # CLI commands with self-registration
│   ├── commands/       #   Individual command modules
│   ├── registry.ts     #   Command registration system
│   └── index.ts        #   CLI entry point
├── config/             # Configuration management (Zod schemas)
├── cron/               # Scheduled tasks
├── gateway/            # HTTP/WebSocket gateway server
├── heartbeat/          # Proactive monitoring
├── providers/          # LLM provider registry (pi-ai wrapper)
├── session/            # Conversation session management
├── types/              # Shared TypeScript types
└── utils/              # Shared utilities
    ├── logger.ts       #   Logging barrel → `logger/` (context, log-store, …)
    └── helpers.ts      #   Misc helpers

web/                    # Gateway console SPA (React + Vite + Tailwind v4)
└── src/                #   App source; production build → dist/gateway/static/root

extensions/
└── telegram/           # Workspace package: Telegram channel (@xopcai/xopc-extension-telegram)

State directory & workspace on disk

Runtime data (config, credentials, per-agent sessions, the Markdown workspace used as tool cwd and user content, and per-agent bootstrap persona Markdown under agents/<id>/bootstrap/) lives outside the git repo under the state directory (default ~/.xopc). For a filesystem map (bootstrap, agent home, Markdown workspace), see On-disk layout. For setup, env overrides, and how agents.defaults.workspace relates to default paths, see State directory & workspace layout.

Core Modules

Agent Service (src/agent/service.ts)

AgentService is the core orchestrator responsible for:

  1. Message Processing - Receive user messages, call LLM, handle tool calls
  2. Prompt Building - Build system prompt from SOUL.md/USER.md/AGENTS.md/TOOLS.md
  3. Memory - Session message storage and compaction (src/session/); curated agent-home memories/, pluggable memory providers, and tools (src/agent/memory/)
  4. Tool Execution - Unified execution of built-in tools + extension tools
  5. Progress Feedback - Real-time updates for long-running tasks

Prompt Builder (src/agent/prompt/)

Modular prompt building system:

src/agent/prompt/
├── index.ts         # PromptBuilder - main builder
├── modes.ts         # Prompt modes (full/minimal/none)
├── memory/
│   └── index.ts     # memory_search, memory_get tools
└── skills.ts        # Skills loading system

Prompt Sections:

SectionDescription
Identity"You are a personal assistant running in xopc"
Versionxopc version info
Tool Call StyleTool calling style (verbose/brief/minimal)
SafetySafety principles
Memorymemory_search/memory_get usage guide
WorkspaceWorking directory
SkillsSkills system
MessagingMessage sending
HeartbeatsHeartbeat monitoring
RuntimeRuntime info

Built-in Tools (src/agent/tools/)

ToolNameDescription
📄 Readread_fileRead file content (truncated to 50KB/500 lines)
✍️ Writewrite_fileCreate or overwrite file
✏️ Editedit_fileReplace text in file
📂 Listlist_dirList directory contents
💻 ShellshellExecute shell commands (5min timeout)
🔍 SearchgrepText search in files
📄 FindfindFind files by pattern
🔍 Web Searchweb_searchWeb search via Brave Search
📄 Web Fetchweb_fetchFetch web page content
📤 Messagesend_messageSend messages to channels
🔍 Memory Searchmemory_searchSearch memory/*.md snippets in the workspace
📄 Memory Getmemory_getRead memory snippets
🧠 Curated memorycurated_memoryEdit bounded entries in agent-home memories/ (when enabled)
🔎 Session searchsession_searchSearch other sessions’ transcripts (when session store is wired)

Progress Feedback (src/agent/progress.ts)

Real-time progress tracking for long-running tasks:

typescript
// Tool execution feedback
manager.onToolStart('read_file', { path: '/file.txt' });
// → e.g. 📖 Reading...

// Heartbeat for tasks > 30s
manager.onHeartbeat(elapsed, stage);
// → e.g. ⏱️ Running for 45s

Progress Stages:

StageEmojiTrigger
thinking🤔LLM reasoning
searching🔍web_search, grep
reading📖read_file
writing✍️write_file, edit_file
executing⚙️shell commands
analyzing📊Data analysis

Session transcripts & compaction (src/session/)

Session message persistence, search index helpers for session_search, and compaction live under src/session/ (on disk: agents/<id>/sessions/, not the Markdown workspace tree).

Curated & pluggable memory (src/agent/memory/)

src/agent/memory/
├── builtin-memory-store.ts  # agent home memories/MEMORY.md + USER.md (bounded, §-delimited)
├── manager.ts               # MemoryManager — providers, prefetch, sync, onMemoryWrite
├── create-memory-manager.ts # Wires builtin + optional stub from config
├── inject-prefetch.ts       # Prefix user message with <memory-context> when configured
└── …                        # context-fence, providers, plugin discovery

Configured under agents.defaults.memory (Configuration). When the whole subsystem is disabled, curated tools and external prefetch are off.

Compaction (conversation context) is configured under agents.defaults.compaction / pruning in the same defaults object—not the curated memory files above.

Channel plugins (src/channels/)

Channels are implemented as ChannelPlugin instances. The core ChannelManager loads plugins from bundledChannelPlugins in src/channels/plugins/bundled.ts (Telegram is provided by the workspace package extensions/telegram). Each plugin exposes init / start / outbound delivery and optional adapters (config, security, streaming, gateway, etc.).

Features (Telegram):

  • Multi-account support
  • Access control (allowlist, group policies)
  • Streaming message preview
  • Voice messages (STT/TTS)
  • Document/file support

Imports (extension or core code):

typescript
import { telegramPlugin } from '@xopcai/xopc-extension-telegram';
// Re-exported for stable paths: import { telegramPlugin } from './channels/telegram/index.js';

Extension System (src/extensions/)

src/extensions/
├── types.ts       # Extension type definitions
├── api.ts         # Extension API
├── loader.ts      # Extension loader
├── hooks.ts       # Hook system
└── index.ts       # Exports

Hook Lifecycle:

before_agent_start → agent_end → message_received → 
before_tool_call → after_tool_call → message_sending → session_end

Three-tier Storage:

  1. Workspace (workspace/.extensions/) - Project-private
  2. Global (~/.xopc/extensions/) - User-level shared
  3. Bundled (xopc/extensions/) - Built-in

Data Flow

Conversation Flow

User (Telegram/Gateway/CLI)


┌─────────────────────┐
│   Channel Handler   │
└──────────┬──────────┘


┌─────────────────────┐
│   AgentService      │
│  ┌───────────────┐  │
│  │ Load Bootstrap │  │ ← SOUL.md, USER.md, TOOLS.md, AGENTS.md
│  └───────┬───────┘  │
│          ▼          │
│  ┌───────────────┐  │
│  │ Build Prompt  │  │ ← bootstrap files, curated snapshot, memory_search / memory_get, …
│  └───────┬───────┘  │
│          ▼          │
│  ┌───────────────┐  │
│  │ LLM (pi-ai)   │  │
│  └───────┬───────┘  │
│          ▼          │
│  ┌───────────────┐  │
│  │ Execute Tools │  │ ← Tools + Extensions
│  │ + Progress    │  │ ← Progress feedback
│  └───────┬───────┘  │
└──────────┬──────────┘


┌─────────────────────┐
│   Response          │
└──────────┬──────────┘


User Reply / Channel Response

CLI Command Registration

xopc uses self-registration pattern:

typescript
// src/cli/commands/mycommand.ts
import { register } from '../registry.js';

function createMyCommand(ctx: CLIContext): Command {
  return new Command('mycommand')
    .description('My command')
    .action(async () => { ... });
}

register({
  id: 'mycommand',
  factory: createMyCommand,
  metadata: { category: 'utility' },
});

Tech Stack

LayerTechnology
RuntimeNode.js 22+
LanguageTypeScript 5.x
LLM SDK@mariozechner/pi-ai
Agent Framework@mariozechner/pi-agent-core
CLICommander.js
ValidationZod (config) + TypeBox (tools)
LoggingPino
Cronnode-cron
HTTP ServerHono
Web UIReact + Vite + Tailwind v4 (gateway console in web/)
TestingVitest

Extension Points

Adding New Tools

  1. Create src/agent/tools/<name>.ts
  2. Implement AgentTool interface with Typebox schema
  3. Export from src/agent/tools/index.ts
  4. Add to tools array in AgentService

Adding Hooks

typescript
api.registerHook('before_tool_call', async (event, ctx) => {
  // Intercept tool calls
  return { modified: true };
});

Adding channel plugins

  1. Implement ChannelPlugin in a package or under extensions/<name>/ (see src/channels/plugin-types.ts and defineChannelPluginEntry in @xopcai/xopc/extension-sdk).
  2. Export the plugin object and add it to bundledChannelPlugins in src/channels/plugins/bundled.ts if it should ship with the core binary.
  3. Ensure ChannelManager startup loads your plugin (bundled plugins are registered automatically when listed in bundled.ts).

Released under the MIT License.