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 reasoningRuntime boundary
Section titled “Runtime boundary”Bestie stores its normal runtime state under ~/.bestie/:
config.jsonfor non-secret settings.envfor provider keys and bot tokensdata/for SQLite statelogs/for redacted operational logsskills/<skill-name>/SKILL.mdfor installed skillsworkspace/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 onboardbestie chatbestie statusbestie logsbestie doctorbestie memory ...bestie channels telegram|zalo ...bestie cron ...bestie daemon ...bestie service ...bestie tools ...bestie mcp ...bestie skills ...bestie update ...bestie ui
Character and skills
Section titled “Character and skills”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.
LLM provider layer
Section titled “LLM provider layer”Bestie uses config v2 model refs and provider profiles:
llm.primaryis a canonicalprovider/modelref.llm.fallbacks[]stores backup model refs.llm.profilesstores provider, auth mode, optional base URL, andapiKeyEnvnames.llm.modelCatalogmaps 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.
Memory and knowledge graph
Section titled “Memory and knowledge graph”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:
allowstores allowed non-secret candidates directly.askqueues candidates for owner approval.denyrejects writes.
Secrets, tokens, payment details, and raw credentials must not be stored as memory or graph facts.
Channels
Section titled “Channels”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 and background runtimes
Section titled “Cron and background runtimes”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|allfor manual detached local processes.bestie service installfor OS-managed user startup: one Linuxbestie.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.
Tools, MCP, and subagents
Section titled “Tools, MCP, and subagents”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.
Permission model
Section titled “Permission model”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.
Local web console
Section titled “Local web console”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.
Future boundaries
Section titled “Future boundaries”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.
