10 · Engineering Practices & Appendix
Tenth installment of the architecture deep-dive: complete environment variable reference, GPU tiers, VRAM gating, code organization quick reference, build & run, and external agent adaptation. Corresponds to
ARCHITECTURE.md§12–§15.
§12 External Agent Adaptation
- Supports integrating user-run external agents (hosts of custom skills / custom pipelines)
- External agents participate in the same graph via bridge REST + tool gateway
- IDENTITY.md template is generated by
_external_identity_md()
python
# src/models/assistant.py
def _external_identity_md(*, kind: str, display_name: str,
cli_path: str, workspace_dir: str,
base_url: str, model: str) -> str:
"""Minimal IDENTITY.md for externally-backed agent."""
return (
f"# {display_name}\n\n"
f"This agent is a **proxy** for an external AI runtime...\n"
)§13 Complete Environment Variable Reference
13.1 LLM Configuration (LLMConfig)
| Variable | Required | Default | Description |
|---|---|---|---|
BASE_URL | ✅ | — | OpenAI-compatible API base URL |
API_KEY | ✅ | — | API key |
DEFAULT_MODEL | ✅ | — | Default chat model |
MANAGER_MODEL | — | "gpt-4o" | Manager executive summary model |
MINI_MODEL | — | "Qwen2.5-1.5B" | Lightweight local model |
FAST_MODEL | — | "" | Low-latency fast model (empty = fall back to DEFAULT_MODEL) |
BETA | — | 0.3 | Cost weight in model routing formula |
13.2 Infrastructure (InfrastructureConfig)
| Variable | Required | Default | Description |
|---|---|---|---|
TIMEOUT | — | 300 | HTTP timeout (seconds) |
MAX_TURNS | — | 50 | Maximum tool-call loop iterations |
DIALOGUE_EXPIRE_TIME | — | 3600 | Dialogue expiration time (seconds) |
SLIDE_WINDOW_SIZE | — | 5 | Dialogue history sliding window size |
WORKSPACE_ROUTE | — | "" | Root working directory (empty = cwd) |
TOP_K | — | 5 | RAG recall top-K |
13.3 Embedding Configuration (EmbeddingConfig)
| Variable | Required | Default | Description |
|---|---|---|---|
EMBEDDING_MODEL | — | "BAAI/bge-m3" | Sentence-transformers model |
BASE_ROUTE | — | "" | Root directory for local model/router files |
13.4 Circuit Breaker Configuration (CircuitBreakerConfig)
| Variable | Required | Default | Description |
|---|---|---|---|
CB_FAILURE_THRESHOLD | — | 5 | Number of failures before circuit opens |
CB_RECOVERY_SECONDS | — | 30.0 | Recovery time before half-open probe (seconds) |
LLM_MAX_RETRIES | — | 3 | Maximum retries per LLM call |
LLM_RETRY_BASE_DELAY | — | 1.0 | Initial backoff delay (seconds) |
LLM_RETRY_MAX_DELAY | — | 30.0 | Maximum backoff delay (seconds) |
LLM_MAX_CONCURRENT_PER_URL | — | 8 | Maximum concurrent LLM calls per URL (AIMD upper bound) |
LLM_MIN_CONCURRENT_PER_URL | — | 1 | AIMD shrink lower bound |
LLM_QUEUE_WAIT_S | — | 120 | Maximum seconds to wait for gate permission |
LLM_AIMD_GROW_AFTER | — | 20 | Number of consecutive successes before AIMD target +1 |
LLM_AIMD_SHRINK_FACTOR | — | 0.5 | AIMD target multiplier on timeout |
LLM_GATE_DISABLED | — | False | Completely disable the concurrency gate |
13.5 GPU / VRAM Configuration
| Variable | Required | Default | Description |
|---|---|---|---|
FAMILIARS_TIER4_MAX_MB | — | 5000 | tier4 VRAM upper bound (MiB) |
FAMILIARS_TIER6_MAX_MB | — | 7500 | tier6 VRAM upper bound (MiB) |
FAMILIARS_GPU_TIER | — | auto | Override auto-detection (mode0/tier4/tier6/tier8) |
FAMILIARS_GPU_TIER_FORCE_REDETECT | — | 0 | Force re-detection of GPU tier |
13.6 Security Configuration
| Variable | Required | Default | Description |
|---|---|---|---|
FAMILIARS_APPROVAL_DISABLED | — | 0 | 1 = completely skip the approval gate |
13.7 Bridge Configuration
| Variable | Required | Default | Description |
|---|---|---|---|
FAMILIARS_HTTP_INSECURE | — | 0 | 1 = fall back to uvicorn + HTTP |
FAMILIARS_DAEMON | — | 0 | 1 = daemon mode (pidfile + log redirection) |
FAMILIARS_DB_PATH | — | workspace/familiars.db | SQLite database path (:memory: for tests) |
FAMILIARS_STREAM_LLM | — | auto | true/false to override streaming decisions |
BRIDGE_PORT | — | 18711 | Bridge listening port |
13.8 External Service Configuration
| Variable | Required | Default | Description |
|---|---|---|---|
HUGGING_FACE_API_KEY | — | "" | Hugging Face API key |
GPT_SOVITS_DIR | — | external/GPT-SoVITS | GPT-SoVITS bundle path |
THA3_DIR | — | external/talking-head-anime-3-demo | THA3 checkout path |
DATAGEN_BASE_URL | — | "" | Data generation API base URL |
DATAGEN_API_KEY | — | "" | Data generation API key |
§14 GPU Tiers (src/base/gpu_tier.py)
14.1 Tier Matrix
python
Tier = Literal["mode0", "tier4", "tier6", "tier8"]
# Thresholds (MiB, as reported by nvidia-smi)
_TIER4_MAX_MB = float(os.getenv("FAMILIARS_TIER4_MAX_MB", "5000"))
_TIER6_MAX_MB = float(os.getenv("FAMILIARS_TIER6_MAX_MB", "7500"))| Tier | VRAM Range | Feature Set |
|---|---|---|
mode0 | No GPU | API-only (no local models) |
tier4 | ≤5000 MiB | 4-bit + sequential loading; decider/memorizer queue-triggered |
tier6 | ≤7500 MiB | rewriter+embedder+reranker co-resident; audio calls allowed |
tier8 | >7500 MiB | Full feature set |
14.2 Detection Flow
python
def _probe_total_vram_mb() -> Optional[float]:
"""nvidia-smi --query-gpu=memory.total --format=csv,noheader,nounits
Apple Silicon / macOS has no nvidia-smi → mode0 (unless FAMILIARS_GPU_TIER overrides).
Result is cached to workspace/gpu_tier.json.
"""14.3 Transient Downgrade
python
# _transient_tier: Optional[Tier] = None
# User selects "downgrade tier" in the frontend → sets _transient_tier
# Does not write to gpu_tier.json → next startup restores auto-detection§15 VRAM Gating (src/base/vram_gate.py)
15.1 Priority Taxonomy
python
# Priority taxonomy (lower = more important):
# 1 — CRITICAL Active user requests (TTS speaking, operate() in flight, LLM generating)
# 2 — IMPORTANT Steady-state user interaction (selected agent's decider, bge embedding, reranker)
# 3 — NICE Useful but can wait (memorizer writer, mini-model, EasyOCR, emotion tagger)
# 4 — BACKGROUND Indexing/training (never user-visible)15.2 Entry Structure
python
@dataclass
class _Entry:
model_id: str
priority: int
estimated_mb: float
on_evict: Optional[Callable[[], None]] = None
is_subprocess: bool = False
category: Literal["sync", "queue"] = "sync"
is_working: bool = False
on_checkpoint: Optional[Callable[[], Any]] = None
admitted_at: float = field(default_factory=time.monotonic)
last_active_at: float = field(default_factory=time.monotonic)
idle_ttl_sec: Optional[float] = None15.3 Category Semantics
| Category | Description | Eviction Rule |
|---|---|---|
sync | User-blocking. UI actions load synchronously | Can evict idle residents or queue residents |
queue | Interruptible background work | Runs on_checkpoint() snapshot on eviction |
15.4 Never-Dropped Guarantee
acquired()blocks onCondition.wait()- Any
release/update_prioritycallsnotify_all() - Caller exception → entry released, slot not held indefinitely
- The only non-admission path: explicit
timeoutparameter →TimeoutError
15.5 Thread Priority Boost
python
@contextmanager
def boost_thread_priority(priority: int) -> Iterator[None]:
"""Temporarily boost priority for user-blocking threads.
Nested calls take the min → inner CRITICAL + outer NICE = inner CRITICAL.
Prevents inner boosts from accidentally weakening outer guarantees.
"""Usage:
python
from src.base.vram_gate import boost_thread_priority, PRIORITY_CRITICAL
with boost_thread_priority(PRIORITY_CRITICAL):
do_user_facing_work() # All gate.acquired() calls inside are CRITICAL§16 Code Organization Quick Reference
16.1 Core Jump Table
| File | Responsibility |
|---|---|
src/bridge/app.py | FastAPI mounting, CUDA pin, JIT model load, autorun, monitor rehydrate |
src/bridge/deps.py | DI providers (AssistantManager/DialogueManager/CommHub/UsageTracker) |
src/bridge/run.py | Bridge startup entry (hypercorn + HTTPS/2) |
src/models/assistant.py | Assistant + AssistantManager (lifecycle/reports/persona evolution) |
src/models/conversation.py | ConversationSession + DialogueManager + RAG composition |
src/models/transferer.py | Cross-agent / cross-client / cross-model dispatch (6 priority levels) |
src/models/clients/base_client.py | ToolClient base — tool loop, history pruning, schema normalization |
src/tools/tool_dispatcher.py | Tool name → callable table (15 default tool instances) |
src/tools/security.py | Risk levels / approval gate / dynamic score escalation |
src/tools/sensitive_detector.py | Three-layer sensitive info detection (gitleaks + presidio + mini-LLM) |
src/base/crypto.py | Crypto primitives (HKDF b"familiars-secrets-v1") |
src/utils/browser_tools.py | Chrome CDP automation (single shared instance) |
src/utils/memory_tools.py | Node, DialogTree, Memorizer |
src/utils/memory_store.py | Memory storage layer (scope × category matrix) |
src/utils/daily_tools.py | Schedule/todo/reminder/report tools |
src/utils/reminder_dispatch.py | Reminder dispatch (inbox.jsonl + native notifications) |
src/base/vram_gate.py | Single VRAM admission gate (4 priority levels / sync+queue categories) |
src/base/gpu_tier.py | GPU tier detection (mode0/tier4/tier6/tier8) |
src/base/config.py | pydantic-settings Settings aggregate + validate_config() |
src/storage/db.py | SQLite WAL + migration runner (v1…v50) |
src/broker/hub.py | Broker layer root (identity/transport/matching/rate-limiting/ledger) |
src/flow/engine.py | FlowEngine concurrent execution |
src/flow/resume.py | Resume from breakpoints (mutation log + hash verification) |
src/digital_human/session.py | DigitalHumanSession (three-task async pipeline) |
src/digital_human/config.py | DigitalHumanConfig |
electron/electron/main.js | Electron main process |
electron/electron/python.js | Bridge lifecycle (port probe/health check/subprocess management) |
16.2 Tool Class Jump Table
| Tool Class | Source File | Example Methods |
|---|---|---|
BaseTools | src/utils/base_tools.py | read, write, execute_shell_script, find, grep, download |
BaseTools.InputController | Embedded in BaseTools | keyboard_type, keyboard_write |
BrowserTools | src/utils/browser_tools.py | browser_open, browser_click, browser_type, explore_page |
MultimodalTools | src/utils/multimodal_tools.py | vision_describe, operate, screenshot |
DailyTools | src/utils/daily_tools.py | create_schedule, create_todo, create_reminder |
DailyMonitorTools | src/utils/daily_monitor/ | Daily context collection |
DocTools | src/utils/doc/tools.py | read_docx, write_docx, generate_ppt, generate_excel |
MemoryTools | src/utils/memory_tools.py | read_memory, write_memory, rag_query |
SystemTools | src/utils/system_tools.py | get_system_info, network_info |
UserTools | src/utils/user_tools.py | get_user_profile, update_user_profile |
UserSecretTools | src/utils/user_secret_tools.py | get_user_secret, store_user_secret |
PhoneTools | src/utils/phone_tools.py | Phone-related operations |
SkillTools | src/tools/skill_tools.py | execute_skill |
SkillWatcherTools | src/utils/skill_watcher_tools.py | Skill change monitoring |
BrokerTools | src/utils/broker_tools.py | Broker operations |
§17 Build & Run
17.1 Development Environment
bash
# Python environment
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txt
# Configuration
cp .env.example .env # Edit .env to fill in API configuration
# Start Bridge
python -m src.bridge.run # HTTPS/2 on 127.0.0.1:18711
# Start Electron (development mode)
cd electron && npm run electron:dev17.2 CLI
bash
# CLI drives the running bridge (X-Bridge-Token auto-read from workspace/.bridge_token)
python main.py --help # 39 command groups, 200+ subcommands
python main.py agents list --pretty
python main.py chat stream --prompt "hi" --agent-id 1
python main.py todos create --title "buy milk" --deadline 2026-07-05T18:00Full reference: CLI Command Reference.
17.3 Production Build
bash
cd electron && npm run electron:build17.4 Testing
bash
# All tests must use a real SQLite
FAMILIARS_DB_PATH=:memory: pytest
# Specific modules
pytest test/recipes/ # Recipe tests (300+)
pytest test/bridge/ # Bridge tests
pytest test/models/ # Model tests17.5 Production Relay
deploy/relay/app/ # Docker + Caddy, Cloudflare DNS-01§18 Key Design Constraints
18.1 CUDA First-Touch Thread
Windows WDDM does not allow a worker thread to first-touch CUDA.
src/bridge/app.py executes torch.cuda.init() + torch.zeros(1, device="cuda") at import time.
Violation → process crashes with 0xC0000005 (access violation).18.2 Path Alignment Timing
align_all_paths() must run before DialogueManager._load_existing_dialogues.
Otherwise stale paths are read into context → LLM loops ls-ing ghost paths.18.3 Port Stability
18711 is the default port, not a fixed port.
The port file workspace/.bridge.port is the actual signal.
The CLI reads the port file; Electron writes it after probing.
The autorun watchdog always uses 18711; Electron calls pickFreePort() when a conflict is found.18.4 Single Embedder Instance
No DialogTree caches model instances (properties route to the singleton getter).
Allows unload_embedding_model to release ~700MB of VRAM.
Old version: N dialogues = N refs → after eviction CUDA tensors still referenced → TTS admission fails.18.5 consult_doc Is Still Active
_CONSULT_TARGETS in src/models/clients/base_client.py still routes consult_doc → doc_tools.
Historical claims that "consult_doc was removed" are wrong → the mapping is still live and used by planners.§19 Appendix: Migration List
See the complete migration list in 05-Persistence Layer §6.4.2.
Current version: v46 (v46__guild_task_tags.sql).
End of the ten-part architecture deep-dive. Continue: Developer Guide or Ecosystem Development Tutorials.
