In one breath
- ReliBot (The Hartford): incident-response agent for SRE and dev teams. Asked in Teams, CLI or web chat, it pulls Splunk logs, Dynatrace problems, recent GitHub deploys and scanner results, and answers with evidence.
- MyClawBot (personal): 12 bot instances on Telegram and WhatsApp, built on the Claude Agent SDK. The proving ground for the same memory, bridge and security patterns.
- What sets them apart: long-term memory that recalls past fixes, and a fail-closed tool policy on every call.
Key numbers
| Tools | 80+ in 16 domains (ReliBot) · 228 MCP tools (MyClawBot) |
| Sub-agents | 12, called as AgentTool |
| Tests | 2,200+ (ReliBot) · ~3,500 (MyClawBot, gate < 60 s) |
| Embeddings | 384-d, local (bge-small / MiniLM) |
| Session rotation | 50K tokens or 50 messages |
| Tool limits | 30 s timeout · max 5 calls per tool per agent |
| Retry backoff | 1 / 3 / 8 s · breaker opens after 2 failures |
| Conversation TTL | 90 days |
Request path
- Channel: Teams (Bot Framework JWT/JWKS + tenant check), CLI, web chat (WebSocket).
- Bridge: per-user rate limit → input injection scan → session rotation.
- ADK callbacks around the root agent:
before_model_callback: inject L1/L2/L3 recallbefore_tool_callback: fail-closed allowlist + call capafter_tool_callback: scan tool output for injection
- Models: Vertex AI Gemini 3 Pro → 3 Flash → 3.1 Flash → 3.1 Flash-Lite.
- Post-turn: log the conversation, auto-save incident fixes and insights.
Recall layers (ReliBot)
| Layer | Holds | Budget |
|---|---|---|
| L1 Core | MEMORY.md: preferences, standing decisions |
≤ 8K chars, always on |
| L2 Recent | this chat, by chat_key |
4 days, ≤ 20K chars |
| L3 Entity | services or people mentioned | ≤ 6 entities, ≤ 9.6K chars |
| Search | everything else | on demand (search_notes) |
- L1–L3 are pure SQL, no LLM call, injected on the first model call only.
- L3 matching is a substring / word-boundary check against a cached top-1K entity list: microseconds.
Ranking formulas
- Hybrid:
0.7 · vector + 0.3 · BM25 - Graph mode:
0.5 · hybrid + 0.3 · graph + 0.2 · entity - MyClawBot adds: × recency decay (30-day half-life) → MMR re-rank (λ = 0.7) over a 3× over-fetch.
- Caching the embedding matrix took search from 4.6 s to 58 ms.
Write path
- During the turn: the model calls
save_memory. - Post-turn auto-save: ≥ 2 incident tools used and nothing saved →
incident-resolutions/. - Insights: answer ≥ 500 chars or > 2 turns →
insights/. - Heartbeat flush (idle 15 min or nightly): Gemini Flash pass 1 → Context · Decisions · Lessons · Actions; pass 2 → facts, SHA-1 dedup.
- Indexing on save: chunk 1,500 chars → local ONNX embedding + FTS5 triggers + regex entities (sync) + LLM entity extraction on an
asyncio.Queue(async).
Storage
- ReliBot: one SQLite file in WAL mode:
notes+ FTS5,chunks+ sqlite-vec,entities/relationships,conversations+ FTS5,incidents. - MyClawBot: a markdown vault is the source of truth (git-trackable). The SQLite index is rebuildable, and unchanged files are skipped by content hash.
- Why SQLite: each instance is team-scoped (~2.5K chunks, ~500 notes). Millisecond queries, zero ops, one file to back up.
Guardrails
- Fail-closed tool allowlist, enforced in code.
- Call caps in code: Gemini sub-agents called
search_notes15+ times and prompt instructions didn't stop them. - Memory is an injection persistence vector: text saved once is replayed every turn. So
MEMORY.mdis sanitized, tool output is scanned, and compression input is fenced as quoted data. - Isolation: one subprocess and data directory per team instance, run by a manager process.
Reliability
- Failover chain with retry backoff 1 / 3 / 8 s.
- Circuit breaker opens after 2 failures, so a bad model is skipped instead of paying its timeout on every request.
- Replies served by a fallback are tagged
[fallback: model]. - Bounded growth: session rotation (summary written first), 90-day TTL, SHA-1 fact dedup.
ReliBot vs MyClawBot
| ReliBot | MyClawBot | |
|---|---|---|
| Runtime | ADK + Gemini | Claude Agent SDK, Haiku / Sonnet / Opus router |
| Source of truth | SQLite notes |
markdown vault |
| Recall injected into | system_instruction |
the user message |
| Tools | ADK function tools | in-process MCP @tool |
| Idle flush | Gemini Flash, 15 min | Claude, 10 min |
Prompt-caching rule
- Caching is prefix-based: per-turn recall in the system prompt breaks the cache every turn.
- MyClawBot keys the system prompt on file mtimes and puts dynamic context in the user turn.
- Volatile content goes last.
Design decisions → at scale
| Today | Why | At scale |
|---|---|---|
| SQLite + sqlite-vec | team-scoped, zero ops | Postgres + pgvector, tenant_id + row-level security |
| Keep BM25 next to vectors | rare tokens: FTS5 38/40 recall@10 vs hybrid 0–2/40 | reciprocal-rank fusion or exact-match boost |
| Deterministic recall + on-demand search | injecting everything costs too much; models forget to call memory tools | tune layer budgets per tenant |
| Caps in code, not prompt | prompts didn't stop runaway calls | same |
Token-metering lessons
- Cumulative counter summed as a delta. On resumed sessions the SDK's
total_cost_usdis a running total. Recorded $561.97 vs $144.12 actual: 3.9× (7× on one bot). - Cached tokens.
input_tokensexcludes cache reads and writes, so rotation saw 2–8 tokens while real context passed 300K.
Rules for a metering pipeline:
- idempotent usage events (
event_id), idempotency keys on billing calls - know counter vs gauge vs delta for every provider field
- price input, output, cache-write and cache-read separately
- late or duplicate events: dedup by
event_id, close periods with a grace window - reconcile three ways: usage store vs billing system vs provider invoice
Testing
- LLM mocked at the boundary.
- Storage tests use a real SQLite in
tmp_path: mocking the database hides the bugs that matter. - Deterministic fast gate on every change, full suite before merge.
Acronyms on this sheet
Underlined acronyms show these definitions on hover or tap. Full glossary →
- ADK
- Agent Development Kit Google's open-source framework for building agents and multi-agent systems. ReliBot and GitHubScanner run on it.
- BM25
- Best Match 25 The classic keyword-ranking formula behind SQLite FTS5. Strong on exact tokens such as error codes and CVE IDs.
- CLI
- Command-Line Interface A terminal tool.
- FTS5
- Full-Text Search, version 5 SQLite's built-in full-text index.
- JWKS
- JSON Web Key Set The published public keys used to verify JWT signatures, such as Microsoft's keys for Teams bots.
- JWT
- JSON Web Token A signed token that carries identity claims.
- LLM
- Large Language Model A model such as Gemini or Claude that reads and writes text. Every agent here is an LLM plus tools.
- MCP
- Model Context Protocol An open standard for exposing tools and data to LLM agents. MyClawBot's tools are in-process MCP tools.
- MMR
- Maximal Marginal Relevance A re-ranking step that trades relevance against diversity, so the top results aren't near-duplicates.
- ONNX
- Open Neural Network Exchange A portable model format. ReliBot runs its embedding model locally through ONNX, with no API call.
- SDK
- Software Development Kit A library for building on a platform, such as the Claude Agent SDK.
- SHA-1
- Secure Hash Algorithm 1 A 160-bit hash. Used here for deduplication and snippet-integrity checks, not for security.
- SQL
- Structured Query Language The standard language for querying relational databases.
- SRE
- Site Reliability Engineering The discipline (and teams) that keep production running. ReliBot's main users.
- TTL
- Time To Live How long a record or cache entry is kept before it expires.
- WAL
- Write-Ahead Logging A SQLite journal mode where readers don't block the writer.
More quick reference