Skip to content

Local Cache

ardennguyen edited this page Jun 30, 2026 · 4 revisions

Local Cache (SQLite)

Added in v1.1.0-beta1

zalo-agent stores a per-account SQLite database at:

~/.zalo-agent-cli/accounts/<ownId>/zalo.db

This powers offline/cache-first reads and full-text message search without making network calls.


How the cache is populated

The cache is written passively — it never blocks any command.

Source What gets written
zalo-agent listen Every message, friend event, and group event received
zalo-agent mcp start Every message received via WebSocket (all threads, before filter)
msg history --no-cache Fetched messages are backfilled into the cache
zalo_get_history no_cache=true (MCP) Fetched messages are backfilled into the cache
friend list --no-cache Friend list is re-seeded into the contacts table
conv recent --no-cache Recent chats are re-seeded into the chats table

Cache-first commands (CLI)

These commands read from the local cache by default. Use --no-cache to bypass.

Command Default behaviour --no-cache behaviour
friend list Reads contacts from zalo.db Fetches live from Zalo, re-seeds cache
friend search <name> Searches contacts in zalo.db Fetches live from Zalo, then filters
conv recent Reads chats from zalo.db Fetches live from Zalo, re-seeds cache
msg history <threadId> Reads messages from zalo.db Fetches live from Zalo, backfills cache
msg search <query> FTS5 full-text search on zalo.db (cache-only, no live equivalent)
# Cache-first examples (instant)
zalo-agent friend list
zalo-agent friend search "Phuc"
zalo-agent conv recent
zalo-agent msg history <threadId>
zalo-agent msg search "birthday"

# Bypass cache — force live fetch
zalo-agent friend list --no-cache
zalo-agent friend search "Phuc" --no-cache
zalo-agent conv recent --no-cache
zalo-agent msg history <threadId> --no-cache

Cache-first in MCP tools

The zalo_get_history MCP tool supports cache-first via the no_cache parameter.

// Cache-first (default) — returns source: "cache"
{ "threadId": "uid123", "limit": 50 }

// Force live fetch + backfill — returns source: "live"
{ "threadId": "uid123", "limit": 50, "no_cache": true }

Naming note: MCP tool parameters use JSON keys with underscores (no_cache).
CLI flags use POSIX double-dash with hyphens (--no-cache).
Both are correct for their respective interfaces — this is intentional, not a bug.


Full-text search (msg search)

msg search uses SQLite FTS5 (unicode61 tokenizer) to search all cached message content.

# Search all threads
zalo-agent msg search "quarterly report"

# Search within a specific thread
zalo-agent msg search "quarterly report" -t <threadId>

# Limit results
zalo-agent msg search "meeting" -n 10

Supports FTS5 query syntax: AND, OR, NOT, prefix matching (meet*).


Database schema

contacts     — friends + self (uid, display_name, zalo_name, phone, avatar_url)
groups       — group metadata (gid, name, member_count, avatar_url)
chats        — per-thread state (thread_id, thread_type, name, last_active)
messages     — message store (msg_id, thread_id, uid_from, content, timestamp)
messages_fts — FTS5 virtual table over messages.content

WAL mode enabled for concurrent reads while listen/mcp start is writing.


Privacy & permissions

  • Database files use 0600 permissions (owner read/write only) on Unix/macOS.
  • Each account has its own isolated database — no cross-account data leakage.
  • Cache can be deleted at any time: rm ~/.zalo-agent-cli/accounts/<ownId>/zalo.db

When the cache is empty

If no listen or mcp start has run yet, cache-first commands fall back to live Zalo fetches automatically — so you never see an empty result just because the cache is cold.

# On first run (no cache) — automatically falls back to live
zalo-agent friend list       # Falls back to live Zalo API
zalo-agent msg history <ID>  # Falls back to live Zalo API

# msg search has no live fallback — use listen first to seed
zalo-agent msg search "term"  # Returns: cache not seeded — run 'listen' first

Clone this wiki locally