Skip to content

Architecture

Bestie is a local-first, self-hostable AI companion and controlled action runtime. The same core runtime serves terminal chat, Telegram, Zalo, cron schedules, installed skills, MCP read foundations, permission-gated tools, bounded subagents, and the local web console.

Terminal / Telegram / Zalo / Cron / Local UI
-> Channel or UI adapter
-> Shared runtime loop
-> Character prompt + installed skills
-> Memory router + knowledge graph retrieval
-> LLM provider adapter
-> Tool loop + MCP router
-> Safety / permission layer
-> Response or action proposal
-> Redacted logs + memory/knowledge reasoning

Bestie stores its normal runtime state under ~/.bestie/:

  • config.json for non-secret settings
  • .env for provider keys and bot tokens
  • data/ for SQLite state
  • logs/ for redacted operational logs
  • skills/<skill-name>/SKILL.md for installed skills
  • workspace/ for agent-created files and channel attachments

Config files should name environment variables. Secret values belong in .env, not in JSON config, docs, screenshots, or logs.

The CLI owns user-facing commands and should stay thin. Reusable behavior belongs in runtime services.

Current command surfaces include:

  • bestie onboard
  • bestie chat
  • bestie status
  • bestie logs
  • bestie doctor
  • bestie memory ...
  • bestie channels telegram|zalo ...
  • bestie cron ...
  • bestie daemon ...
  • bestie service ...
  • bestie tools ...
  • bestie mcp ...
  • bestie skills ...
  • bestie update ...
  • bestie ui

Bestie loads editable local character files and installed skills before building a prompt.

The character system should stay data-driven through local files such as character.json and system-prompt.md. Skills live under ~/.bestie/skills/<skill-name>/SKILL.md and add reusable workflow instructions when relevant.

The character may be funny, blunt, and playful, but it must not humiliate the user, pretend to be human, claim therapy authority, claim romance, or joke during unsafe crisis moments.

Bestie uses config v2 model refs and provider profiles:

  • llm.primary is a canonical provider/model ref.
  • llm.fallbacks[] stores backup model refs.
  • llm.profiles stores provider, auth mode, optional base URL, and apiKeyEnv names.
  • llm.modelCatalog maps model refs to profiles.

Supported local development setup paths include OpenAI/ChatGPT, Anthropic Claude, Groq, OpenRouter, custom OpenAI-compatible endpoints, custom Anthropic-compatible endpoints, local Ollama, and native Gemini API-key mode.

Provider failures and fallback chains are logged with secret redaction and surfaced through Doctor, status, and provider diagnostics without printing raw keys.

Bestie starts with local SQLite memory. The memory layer supports approved memories, pending memories, persisted messages, pause/resume state, governance metadata, cleanup planning, and owner review commands.

The knowledge graph extends local memory with entities and relations. It supports local inspection, search, hygiene analysis, pending graph writes, review suggestions, merge/update/forget operations, and compact retrieval into chat prompts when relevant.

Memory and graph writes follow policy:

  • allow stores allowed non-secret candidates directly.
  • ask queues candidates for owner approval.
  • deny rejects writes.

Secrets, tokens, payment details, and raw credentials must not be stored as memory or graph facts.

Channel adapters translate platform events into runtime messages and send runtime responses back.

Current channels:

  • Telegram: local long polling, owner allowlist, slash commands, attachments, voice-capable workflows through shared voice config, edited tool progress messages, Doctor summaries, memory controls, and approvals.
  • Zalo: local text polling, owner allowlist, slash commands, typing indicators, long reply splitting, memory controls, provider diagnostics, transcript debugging, and approvals.
  • Cron: scheduled isolated agent turns that can report to Telegram or Zalo destinations.

Channel adapters should remain thin. Authentication, polling, upload formats, and platform quirks stay in the adapter. Shared prompt building, memory, tools, permissions, and logging stay in runtime services.

Cron schedules are stored locally and run later as isolated Bestie turns. Use them for reminders, periodic checks, daily reports, and background reviews.

Background execution has two layers:

  • bestie daemon --channel telegram|zalo|cron|all for manual detached local processes.
  • bestie service install for OS-managed user startup: one Linux bestie.service, macOS LaunchAgents, or a Windows Startup shortcut.

Avoid running duplicate background modes for the same target. Duplicate polling or duplicate cron execution is not productivity; it is a tiny automation goblin with a megaphone.

Bestie can use internal tools for local inspection, file edits, patches, exec, process listing, web reads, git context, memory, knowledge graph, and cron management when the configured permission policy allows it.

MCP support is SDK-backed and currently strongest for setup, OAuth login, tool discovery, classification, and classified read calls. Broader MCP execution categories should stay behind explicit classification and approval.

Bounded internal subagents can perform focused helper investigations inside the existing tool loop. They do not replace Bestie’s user-facing voice and cannot recursively spawn more subagents.

Every action beyond a plain text reply should be classified:

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

Trusted reads can be allowed. Local writes, external writes, destructive actions, public actions, money actions, and unknown tools should ask or deny by default unless the owner explicitly configures a trusted path.

The controlled-autonomy rule is simple: prepare safe work automatically, require approval for risky work, and always leave a receipt.

bestie ui starts a local web console that reuses the same runtime state. It exposes status, Doctor, Provider Hub, Character Studio, Memory Center, Channels, Approvals, MCP, Tools & Permissions, and Settings panels.

The UI must not become a separate product brain. It should call the same runtime services used by the CLI and channels.

Still-later product directions include optional Zep memory, backup/restore/migration, broader external tools, named ACP/multi-agent orchestration, plugin system, persona templates, avatar/body layer, hosted mode, and broader UI productization.

Do not add those before the local runtime, permissions, Doctor, memory controls, and real-channel behavior can support them.