Skip to content

Architecture

Bestie is a local-first, self-hostable agent runtime. The same core runtime should serve terminal chat, Telegram, future local web UI, MCP integrations, and later multi-agent features.

User / Channel
-> Channel Adapter
-> Runtime Orchestrator
-> Mode Detector
-> Memory Router
-> Prompt Builder
-> LLM Adapter
-> Safety / Permission Layer
-> Tool / Plugin / MCP Router
-> Response
-> Logs + Memory Update

The CLI owns user-facing commands:

  • onboard
  • chat
  • status
  • logs
  • doctor
  • memory
  • telegram
  • tools
  • mcp

CLI commands should call runtime services instead of duplicating business logic. Installer, update, and backup commands are later milestones.

The runtime coordinates a turn:

  1. Receive a message from terminal, Telegram, or another adapter.
  2. Load config, env, character files, and memory context.
  3. Build the prompt.
  4. Call the configured OpenAI-compatible LLM.
  5. Execute approved tool loops when needed.
  6. Send the response.
  7. Store redacted logs and approved memory updates.

The current runtime supports approved local memory recall, explicit memory writes, permission-gated read tools, a multi-step tool loop, and Doctor diagnostics. Broader external, destructive, and public-action tools remain later work.

Bestie loads editable local character files such as:

  • character.json
  • system-prompt.md
  • style examples
  • safety boundaries

The product goal is a believable best-friend character: witty, blunt, emotionally sharp, loyal, and practical. The character can tease and push back, but must not humiliate, diagnose, pretend to be human, or encourage harm.

The first adapter is OpenAI-compatible HTTP chat completions.

Required config:

  • baseUrl
  • apiKeyEnv
  • model

Useful optional config:

  • timeoutMs
  • maxRetries
  • retryDelayMs
  • temperature and max-token settings as the implementation expands

Provider errors are normalized for Doctor, logs, and user-facing messages.

The current memory foundation uses local SQLite. It stores active memories, pending memories, persisted terminal and Telegram messages, pause state, and pending action approvals.

Future memory work may add optional Zep, memory merge logic, and richer sensitive-memory approval flows. Zep should add context; it should not define the character.

Telegram is the first real channel. It uses long polling, owner-only access, slash commands, typing indicators, edited progress messages, attachment handling, memory controls, Doctor summaries, and approval prompts.

Channel adapters should stay thin. Shared behavior belongs in runtime services so terminal and Telegram do not drift.

Doctor is a first-class diagnostic module. It checks environment, config, providers, memory, channels, logs, services, and character files.

bestie doctor --fix only performs safe local repairs unless an action explicitly requires confirmation.

Every action beyond text reply should pass through a permission classifier:

  • read-only
  • local write
  • external write
  • public action
  • destructive
  • money/payment
  • unknown

The current local foundation allows trusted read-only actions, asks or denies riskier categories by default, logs decisions with secret redaction, and exposes internal read tools for terminal and Telegram.

MCP support currently focuses on classified read-only calls through local config. Broader MCP, plugins, and multi-agent features should wait until Doctor, logging, permissions, and real-channel behavior are mature.