# Familiar - Self-Hosted AI Companion Platform
# Copyright (c) 2026 George Scott Foley
# ORCID: 0009-0006-4957-0540
# Email: Georgescottfoley@proton.me
# Licensed under the MIT License - see LICENSE file for details

"""Familiar Installation & User Guide — PDF and HTML generation.

Provides:
    get_guide_html()          — returns the full guide as an HTML string
    generate_guide_pdf(path)  — renders to PDF via WeasyPrint (optional dep)

The generated PDF is cached at ``~/.familiar/data/familiar_guide.pdf``
and regenerated only when the package version changes.
"""

from __future__ import annotations

import logging
from pathlib import Path

logger = logging.getLogger(__name__)

# ── STYLES (shared across entire document) ──────────────────────────
STYLES = """
  @page {
    size: A4;
    margin: 2.0cm 1.8cm 2.3cm 1.8cm;
    @bottom-center {
      content: "Page " counter(page) " of " counter(pages);
      font-size: 8px; color: #888; font-family: 'Segoe UI', Arial, sans-serif;
    }
  }
  body { font-family: 'Segoe UI', 'Helvetica Neue', Arial, sans-serif; font-size: 10.5pt; line-height: 1.55; color: #1a1a2e; }
  h1 { font-size: 24pt; color: #0f3460; margin-top: 0; border-bottom: 3px solid #e94560; padding-bottom: 8px; }
  h2 { font-size: 16pt; color: #0f3460; margin-top: 26px; border-bottom: 1.5px solid #ddd; padding-bottom: 4px; page-break-after: avoid; }
  h3 { font-size: 12.5pt; color: #16213e; margin-top: 16px; page-break-after: avoid; }
  h4 { font-size: 11pt; color: #333; margin-top: 12px; page-break-after: avoid; }
  code { background: #f0f0f5; padding: 1px 4px; border-radius: 3px; font-size: 9.5pt; font-family: 'Consolas', monospace; }
  pre { background: #1a1a2e; color: #e0e0e0; padding: 12px 14px; border-radius: 6px; font-size: 9pt; line-height: 1.45; overflow-wrap: break-word; white-space: pre-wrap; page-break-inside: avoid; }
  pre code { background: none; padding: 0; color: inherit; }
  table { border-collapse: collapse; width: 100%; margin: 8px 0 14px 0; font-size: 9.5pt; page-break-inside: avoid; }
  th { background: #0f3460; color: #fff; padding: 6px 8px; text-align: left; }
  td { padding: 5px 8px; border-bottom: 1px solid #ddd; vertical-align: top; }
  tr:nth-child(even) td { background: #f8f8fc; }
  .cover { text-align: center; padding-top: 140px; page-break-after: always; }
  .cover h1 { font-size: 34pt; border: none; margin-bottom: 6px; }
  .cover .subtitle { font-size: 14pt; color: #555; margin-bottom: 30px; }
  .cover .version { font-size: 11pt; color: #888; }
  .cover .author { font-size: 10pt; color: #666; margin-top: 50px; }
  .toc { page-break-after: always; }
  .toc a { color: #0f3460; text-decoration: none; }
  .toc li { margin-bottom: 4px; }
  .tip { background: #eef6ff; border-left: 4px solid #4A90D9; padding: 10px 14px; margin: 10px 0; border-radius: 0 4px 4px 0; page-break-inside: avoid; }
  .warn { background: #fff8e6; border-left: 4px solid #ffb347; padding: 10px 14px; margin: 10px 0; border-radius: 0 4px 4px 0; page-break-inside: avoid; }
  .danger { background: #ffe6e6; border-left: 4px solid #e94560; padding: 10px 14px; margin: 10px 0; border-radius: 0 4px 4px 0; page-break-inside: avoid; }
  .step { background: #f4f4ff; border: 1px solid #ddd; border-radius: 6px; padding: 12px 16px; margin: 10px 0; page-break-inside: avoid; }
  .step-num { display: inline-block; background: #0f3460; color: #fff; width: 24px; height: 24px; border-radius: 50%; text-align: center; line-height: 24px; font-size: 12px; font-weight: bold; margin-right: 8px; }
  .section { page-break-before: always; }
  .section:first-of-type { page-break-before: auto; }
  ul, ol { padding-left: 22px; }
  li { margin-bottom: 3px; }
  /* Appendix uses slightly smaller text to fit dense reference tables */
  .appendix table { font-size: 8.5pt; }
  .appendix td code { font-size: 8pt; }
  .appendix h3 { font-size: 11pt; }
  .appendix h4 { font-size: 9.5pt; }
"""

# ── MAIN GUIDE (sections 1-17) ──────────────────────────────────────
MAIN_GUIDE = r"""
<!-- ==================== COVER ==================== -->
<div class="cover">
  <h1>Familiar</h1>
  <div class="subtitle">Self-Hosted AI Companion Platform</div>
  <div class="subtitle" style="font-size:13pt;">Installation &amp; User Guide</div>
  <div class="version">Version 1.15.6 &mdash; March 2026</div>
  <div class="author">
    George Scott Foley<br>
    ORCID: 0009-0006-4957-0540<br>
    <code>Georgescottfoley@proton.me</code><br><br>
    <span style="font-size:10pt;color:#999;">MIT License &bull; <code>pip install familiar-agent</code></span>
  </div>
</div>

<!-- ==================== TOC ==================== -->
<div class="toc">
<h2>Table of Contents</h2>
<p style="color:#555; font-size:10pt; margin-bottom:16px;">This guide is written for first-time users who have never set up an AI agent before. Every section walks you through each step. If you get stuck, jump to Section 20 (Troubleshooting).</p>
<ol style="font-size:10.5pt;">
  <li><a href="#s1">What Is Familiar?</a></li>
  <li><a href="#s2">Before You Start &mdash; What You Need</a></li>
  <li><a href="#s3">Getting an API Key (Step by Step)</a></li>
  <li><a href="#s4">Installing Familiar</a></li>
  <li><a href="#s5">First-Time Setup &mdash; The Onboarding Wizard</a></li>
  <li><a href="#s6">Running Familiar for the First Time</a></li>
  <li><a href="#s7">The Web Dashboard &mdash; Your Control Panel</a></li>
  <li><a href="#s8">Meet Your Creature &mdash; Choosing &amp; Customizing</a></li>
  <li><a href="#s9">Job Classes &amp; Workspace Panels</a></li>
  <li><a href="#s10">Talking to Your Familiar &mdash; Chat Commands</a></li>
  <li><a href="#s11">Connecting Channels (Telegram, Discord, etc.)</a></li>
  <li><a href="#s12">Choosing Your AI Brain &mdash; LLM Providers</a></li>
  <li><a href="#s13">Skills &mdash; What Your Familiar Can Do</a></li>
  <li><a href="#s14">API Integrations &amp; Service Setup</a></li>
  <li><a href="#s15">Multi-Device Mesh Networking</a></li>
  <li><a href="#s16">Self-Hosted Server Provisioning</a></li>
  <li><a href="#s17">Security &amp; Compliance</a></li>
  <li><a href="#s18">Marketplace &mdash; Custom Packages</a></li>
  <li><a href="#s19">Familiar on Android &amp; the Reflection Platform</a></li>
  <li><a href="#s20">Troubleshooting &amp; FAQ</a></li>
  <li><a href="#s21">Uninstalling, Reinstalling &amp; Clean Reset</a></li>
  <li><a href="#s22">Quick Reference Card</a></li>
  <li style="margin-top:12px; font-weight:bold; color:#0f3460;"><a href="#appendix">Appendix: Advanced Command &amp; Configuration Index</a></li>
</ol>
</div>

<!-- ==================== 1. WHAT IS FAMILIAR ==================== -->
<div class="section" id="s1">
<h2>1. What Is Familiar?</h2>
<p><strong>Familiar</strong> is your own private AI assistant that lives on <em>your</em> computer, not in someone else's cloud. Think of it like having a smart personal assistant that:</p>
<ul>
  <li>Runs on your hardware &mdash; a laptop, desktop, Raspberry Pi, or even your phone</li>
  <li>Connects to the AI "brain" of your choice &mdash; Claude, GPT-4o, Gemini, or completely offline local models</li>
  <li>Comes with a cute evolving pixel creature that grows as you use it</li>
  <li>Has 80+ built-in skills &mdash; email, calendar, CRM, payments, web browsing, voice, documents, and much more</li>
  <li>Has 6 job classes with dynamic workspace panels &mdash; Nonprofit Director, Chef, Artist, and more</li>
  <li>Can talk to you through a web dashboard, Telegram, Discord, and 10+ other platforms</li>
  <li>Manages self-hosted services like Gitea, Nextcloud, Jellyfin, and Mealie with one click</li>
  <li>Lets you browse social media feeds from Bluesky and Mastodon right in your dashboard</li>
  <li>Sends encrypted messages to other Familiar users on your mesh network</li>
  <li>Shares memories and AI models across your devices via encrypted mesh networking</li>
</ul>

<div class="tip">
  <strong>New to AI agents?</strong> An "agent" is an AI that can do things for you &mdash; not just chat, but actually send emails, manage calendars, browse the web, and handle tasks. Familiar is your personal agent that you control completely.
</div>

<h3>How It Works (The Big Picture)</h3>
<ol>
  <li>You <strong>install</strong> Familiar on your computer (takes about 5 minutes)</li>
  <li>You <strong>connect</strong> it to an AI provider (like getting a brain for your assistant)</li>
  <li>You <strong>talk</strong> to it through a web browser, chat app, or terminal</li>
  <li>It <strong>learns</strong> your preferences and gets better over time</li>
  <li>Your <strong>creature</strong> evolves from a baby to an adult as you interact</li>
</ol>
</div>

<!-- ==================== 2. BEFORE YOU START ==================== -->
<div class="section" id="s2">
<h2>2. Before You Start &mdash; What You Need</h2>

<h3>2.1 Your Computer</h3>
<table>
  <tr><th>What</th><th>Minimum</th><th>Recommended</th><th>Why</th></tr>
  <tr><td>Python</td><td>3.10</td><td>3.11 or 3.12</td><td>Familiar is written in Python</td></tr>
  <tr><td>RAM</td><td>512 MB</td><td>4 GB+</td><td>More RAM needed for local AI models</td></tr>
  <tr><td>Disk space</td><td>100 MB</td><td>2 GB+</td><td>Local models need extra space</td></tr>
  <tr><td>Operating system</td><td colspan="2">Linux, macOS, or Windows</td><td>Works on all three</td></tr>
</table>

<h3>2.2 Do I Have Python?</h3>
<p>Open a terminal (Command Prompt on Windows, Terminal on Mac/Linux) and type:</p>
<pre><code>python3 --version</code></pre>
<p>You should see something like <code>Python 3.11.5</code>. If you get an error:</p>
<ul>
  <li><strong>Mac:</strong> Install from python.org or run <code>brew install python</code></li>
  <li><strong>Linux (Ubuntu/Debian):</strong> <code>sudo apt install python3 python3-pip python3-venv</code></li>
  <li><strong>Windows:</strong> Download from python.org &mdash; check "Add Python to PATH" during install</li>
</ul>

<div class="warn">
  <strong>Windows users:</strong> Use <code>python</code> instead of <code>python3</code> in all commands below. Also, use <code>set</code> instead of <code>export</code> for environment variables: <code>set ANTHROPIC_API_KEY=sk-ant-...</code>
</div>

<h3>2.3 Choosing Your AI Provider</h3>
<p>Familiar needs an AI "brain." You have four options &mdash; pick whichever feels right:</p>
<table>
  <tr><th>Option</th><th>Cost</th><th>Quality</th><th>Privacy</th><th>Best For</th></tr>
  <tr><td><strong>Claude</strong> (Anthropic)</td><td>Pay per use (~$3/M tokens)</td><td>Excellent</td><td>Data sent to cloud</td><td>Best overall quality</td></tr>
  <tr><td><strong>GPT-4o</strong> (OpenAI)</td><td>Pay per use (~$2.50/M tokens)</td><td>Excellent</td><td>Data sent to cloud</td><td>Widely used, well-known</td></tr>
  <tr><td><strong>Gemini</strong> (Google)</td><td>Free tier available</td><td>Very good</td><td>Data sent to cloud</td><td>Budget-friendly start</td></tr>
  <tr><td><strong>Ollama</strong> (Local)</td><td>Free forever</td><td>Good to great</td><td>100% private</td><td>Maximum privacy, offline use</td></tr>
</table>

<div class="tip">
  <strong>Not sure?</strong> Start with <strong>Claude</strong> or <strong>Gemini</strong> (free tier). You can switch providers any time &mdash; even mid-conversation &mdash; using the <code>/model</code> command.
</div>
</div>

<!-- ==================== 3. GETTING AN API KEY ==================== -->
<div class="section" id="s3">
<h2>3. Getting an API Key (Step by Step)</h2>

<p>If you chose a cloud provider, you need an API key. This is like a password that lets Familiar talk to the AI. Skip this section if you're using Ollama (local models).</p>

<h3>3.1 Anthropic (Claude)</h3>
<div class="step">
  <span class="step-num">1</span> Go to <strong>console.anthropic.com</strong> in your web browser<br>
  <span class="step-num">2</span> Click "Sign Up" and create an account (email + password)<br>
  <span class="step-num">3</span> Once logged in, click <strong>"API Keys"</strong> in the left sidebar<br>
  <span class="step-num">4</span> Click <strong>"Create Key"</strong>, give it a name like "familiar"<br>
  <span class="step-num">5</span> Copy the key &mdash; it starts with <code>sk-ant-</code>. <strong>Save it somewhere safe!</strong> You won't see it again.<br>
  <span class="step-num">6</span> Add a payment method (Settings &rarr; Billing). Claude charges per use, typically $1-5/month for moderate use.
</div>

<h3>3.2 OpenAI (GPT-4o)</h3>
<div class="step">
  <span class="step-num">1</span> Go to <strong>platform.openai.com</strong><br>
  <span class="step-num">2</span> Sign up or log in<br>
  <span class="step-num">3</span> Navigate to <strong>API Keys</strong> (left sidebar or Settings)<br>
  <span class="step-num">4</span> Click <strong>"Create new secret key"</strong><br>
  <span class="step-num">5</span> Copy the key &mdash; starts with <code>sk-</code>. Save it!<br>
  <span class="step-num">6</span> Add billing (Settings &rarr; Billing). Prepay $5-10 to start.
</div>

<h3>3.3 Google Gemini</h3>
<div class="step">
  <span class="step-num">1</span> Go to <strong>aistudio.google.com</strong><br>
  <span class="step-num">2</span> Sign in with your Google account<br>
  <span class="step-num">3</span> Click <strong>"Get API key"</strong> in the top navigation<br>
  <span class="step-num">4</span> Click <strong>"Create API key"</strong><br>
  <span class="step-num">5</span> Copy the key. The free tier is generous enough for personal use.
</div>

<h3>3.4 Ollama (Local &mdash; No Key Needed)</h3>
<div class="step">
  <span class="step-num">1</span> Go to <strong>ollama.com</strong> and download for your OS<br>
  <span class="step-num">2</span> Install it (double-click on Mac/Windows, or follow Linux instructions)<br>
  <span class="step-num">3</span> Open a terminal and run: <code>ollama pull llama3.2</code> (downloads ~2 GB)<br>
  <span class="step-num">4</span> Start the server: <code>ollama serve</code><br>
  <span class="step-num">5</span> That's it! No API key, no payments, everything stays on your machine.
</div>

<div class="tip">
  <strong>Keep your API key secret!</strong> Never share it, post it online, or commit it to Git. Treat it like a password. If you think it's been exposed, revoke it immediately on the provider's website and create a new one.
</div>
</div>

<!-- ==================== 4. INSTALLING FAMILIAR ==================== -->
<div class="section" id="s4">
<h2>4. Installing Familiar</h2>

<h3>4.1 The Easy Way (Recommended for Beginners)</h3>
<p>Open your terminal and run these commands one at a time:</p>

<div class="step">
  <span class="step-num">1</span> <strong>Create a virtual environment</strong> (keeps Familiar separate from your system Python):<br>
  <pre><code>python3 -m venv ~/familiar-env</code></pre>
</div>

<div class="step">
  <span class="step-num">2</span> <strong>Activate the virtual environment:</strong><br>
  <pre><code># Mac/Linux:
source ~/familiar-env/bin/activate

# Windows:
familiar-env\Scripts\activate</code></pre>
  <p style="font-size:9pt; color:#666;">You should see <code>(familiar-env)</code> appear at the start of your terminal prompt. This means you're inside the virtual environment.</p>
</div>

<div class="step">
  <span class="step-num">3</span> <strong>Install Familiar</strong> with cloud LLM support:<br>
  <pre><code>pip install familiar-agent[llm,web]</code></pre>
  <p style="font-size:9pt; color:#666;">This installs the core agent plus Claude/GPT support and the web dashboard. It may take 1-2 minutes.</p>
</div>

<div class="step">
  <span class="step-num">4</span> <strong>Set your API key:</strong><br>
  <pre><code># Mac/Linux:
export ANTHROPIC_API_KEY="sk-ant-your-key-here"

# Windows:
set ANTHROPIC_API_KEY=sk-ant-your-key-here</code></pre>
  <p style="font-size:9pt; color:#666;">Replace with your actual key from Section 3. Use <code>OPENAI_API_KEY</code> or <code>GEMINI_API_KEY</code> if using a different provider.</p>
</div>

<div class="step">
  <span class="step-num">5</span> <strong>Verify the installation:</strong><br>
  <pre><code>python -m familiar --help</code></pre>
  <p style="font-size:9pt; color:#666;">You should see a list of available options. If you get an error, see Section 20 (Troubleshooting).</p>
</div>

<div class="tip">
  <strong>Why a virtual environment?</strong> It creates an isolated space so Familiar's packages don't conflict with anything else on your system. Always activate it (<code>source ~/familiar-env/bin/activate</code>) before using Familiar.
</div>

<h3>4.2 Full Install (All Features)</h3>
<p>If you want everything &mdash; voice, encryption, all channels, document processing:</p>
<pre><code>pip install familiar-agent[full]</code></pre>

<h3>4.3 Minimal Install (Ollama Only, No Cloud)</h3>
<pre><code>pip install familiar-agent[web]</code></pre>
<p>This installs just the core agent + web dashboard. Pair with Ollama for a fully offline setup.</p>

<h3>4.4 Install from Source (Developers)</h3>
<pre><code>git clone https://github.com/omegcrash/familiar.git
cd familiar
pip install -e ".[dev]"</code></pre>

<h3>4.5 Raspberry Pi</h3>
<pre><code># Full automated install with Ollama
./familiar/scripts/install-pi.sh --with-ollama

# Nonprofit preset (calendar, email, bookkeeping)
./familiar/scripts/install-pi.sh --nonprofit</code></pre>

<h3>4.6 Install Extras Reference</h3>
<p>You can install just the features you need. Combine extras with commas:</p>
<pre><code>pip install familiar-agent[llm,discord,telegram,web]</code></pre>
<table>
  <tr><th>Extra</th><th>What It Adds</th><th>When You Need It</th></tr>
  <tr><td><code>llm</code></td><td>Anthropic + OpenAI SDKs</td><td>Using Claude or GPT (most users)</td></tr>
  <tr><td><code>web</code></td><td>Flask dashboard, browser, search</td><td>Web dashboard (most users)</td></tr>
  <tr><td><code>discord</code></td><td>discord.py</td><td>Discord bot channel</td></tr>
  <tr><td><code>telegram</code></td><td>python-telegram-bot</td><td>Telegram bot channel</td></tr>
  <tr><td><code>matrix</code></td><td>matrix-nio (E2EE)</td><td>Matrix channel</td></tr>
  <tr><td><code>slack</code></td><td>slack-sdk</td><td>Slack channel</td></tr>
  <tr><td><code>voice</code></td><td>Whisper, edge-tts, gTTS</td><td>Voice commands &amp; TTS</td></tr>
  <tr><td><code>encryption</code></td><td>cryptography, pynacl</td><td>Encrypting stored data</td></tr>
  <tr><td><code>mesh</code></td><td>Encrypted P2P networking</td><td>Connecting multiple devices</td></tr>
  <tr><td><code>healthcare</code></td><td>Presidio PII/PHI detection</td><td>HIPAA compliance</td></tr>
  <tr><td><code>docs</code></td><td>Word, Excel, PDF, PowerPoint, charts</td><td>Document handling &amp; presentations</td></tr>
  <tr><td><code>google</code></td><td>Google Workspace API</td><td>Google Drive, Calendar, Gmail</td></tr>
  <tr><td><code>redis</code></td><td>Redis backend</td><td>Distributed / multi-instance</td></tr>
  <tr><td><code>email</code></td><td>aiosmtpd</td><td>Self-hosted email server</td></tr>
  <tr><td><code>nextcloud</code></td><td>CalDAV/CardDAV</td><td>Nextcloud integration</td></tr>
  <tr><td><code>bluesky</code></td><td>atproto</td><td>Bluesky social media</td></tr>
  <tr><td><code>mastodon</code></td><td>Mastodon.py</td><td>Mastodon / GoToSocial</td></tr>
  <tr><td><code>training</code></td><td>peft, transformers, accelerate</td><td>LoRA fine-tuning</td></tr>
  <tr><td><code>chain</code></td><td>web3</td><td>On-chain anchoring (L2)</td></tr>
  <tr><td><code>tui</code></td><td>Textual rich terminal UI</td><td>Fancy terminal onboarding</td></tr>
  <tr><td><code>full</code></td><td>All of the above</td><td>You want everything</td></tr>
  <tr><td><code>dev</code></td><td>pytest, ruff, mypy</td><td>Contributing to Familiar</td></tr>
</table>
</div>

<!-- ==================== 5. FIRST-TIME SETUP ==================== -->
<div class="section" id="s5">
<h2>5. First-Time Setup &mdash; The Onboarding Wizard</h2>

<p>Familiar includes a guided setup wizard that walks you through everything. This is the recommended way to configure your agent for the first time.</p>

<h3>5.1 Launch the Wizard</h3>
<pre><code># Option A: CLI wizard (works everywhere)
python -m familiar --onboard

# Option B: Rich terminal UI (prettier, needs [tui] extra)
python -m familiar --onboard-tui

# Option C: Web wizard (great for headless devices like Raspberry Pi)
python -m familiar --dashboard
# Then open http://localhost:5000/onboard in your browser</code></pre>

<h3>5.2 What the Wizard Asks</h3>
<p>The wizard walks you through these steps. Don't worry &mdash; you can change everything later.</p>

<div class="step">
  <span class="step-num">1</span> <strong>LLM Provider</strong> &mdash; Which AI brain to use. The wizard auto-detects available API keys and any running Ollama instance.<br>
</div>
<div class="step">
  <span class="step-num">2</span> <strong>Channels</strong> &mdash; Where you want to talk to your Familiar (CLI, dashboard, Telegram, etc.). Start with just CLI and dashboard.<br>
</div>
<div class="step">
  <span class="step-num">3</span> <strong>Owner Identity</strong> &mdash; Set a PIN so only you can control the agent. This is optional but recommended.<br>
</div>
<div class="step">
  <span class="step-num">4</span> <strong>Your Name</strong> &mdash; So your Familiar can address you properly.<br>
</div>
<div class="step">
  <span class="step-num">5</span> <strong>Creature</strong> &mdash; Pick your companion species (Fox, Owl, Cat, Dragon, Wolf, or Frog) and name it.<br>
</div>
<div class="step">
  <span class="step-num">6</span> <strong>Activation</strong> &mdash; The wizard writes your config file and starts the agent.<br>
</div>

<div class="tip">
  <strong>Need to change settings later?</strong> Run <code>python -m familiar --reconfigure</code> to re-run the wizard at any time. Or edit <code>~/.familiar/config.yaml</code> directly.
</div>

<h3>5.3 LAN Onboarding (Raspberry Pi / Headless Server)</h3>
<p>If you're setting up Familiar on a device without a monitor (like a Raspberry Pi):</p>
<pre><code># On the Pi:
FAMILIAR_ONBOARD_LAN=1 python -m familiar --dashboard

# On your laptop/phone, open:
# http://&lt;pi-ip-address&gt;:5000/onboard</code></pre>
<p>Find your Pi's IP with <code>hostname -I</code> on the Pi.</p>
</div>

<!-- ==================== 6. RUNNING FOR THE FIRST TIME ==================== -->
<div class="section" id="s6">
<h2>6. Running Familiar for the First Time</h2>

<h3>6.1 Start the Agent</h3>
<pre><code># Make sure your virtual environment is active!
source ~/familiar-env/bin/activate    # Mac/Linux
# familiar-env\Scripts\activate       # Windows

# Start with web dashboard (recommended)
python -m familiar --dashboard</code></pre>

<p>You should see output like:</p>
<pre><code>Familiar v1.15.6 starting...
Dashboard running at http://localhost:5000
Agent ready. Type a message or open the dashboard.</code></pre>

<div class="step">
  <span class="step-num">1</span> Open your web browser and go to <strong>http://localhost:5000</strong><br>
  <span class="step-num">2</span> You'll see the dashboard with your creature, a chat window, and settings<br>
  <span class="step-num">3</span> Type <strong>"Hello!"</strong> in the chat box and press Enter<br>
  <span class="step-num">4</span> Your Familiar will respond! Congratulations &mdash; your AI agent is running.
</div>

<h3>6.2 If You See the Tarot Onboarding</h3>
<p>If this is a brand-new setup, the dashboard may show a tarot card spread &mdash; this is the interactive onboarding experience. Follow the cards to complete your setup. You can also trigger it anytime by typing <code>/start</code> in the chat.</p>

<h3>6.3 CLI-Only Mode (No Browser)</h3>
<pre><code>python -m familiar</code></pre>
<p>This starts an interactive chat in your terminal. Type messages and press Enter. Use <code>/help</code> to see available commands. Type <code>/quit</code> to exit.</p>

<h3>6.4 Running in the Background</h3>
<pre><code># Linux/Mac: run in background
nohup python -m familiar --dashboard &amp;

# Or use screen/tmux:
screen -S familiar
python -m familiar --dashboard
# Press Ctrl+A then D to detach. Reattach with: screen -r familiar</code></pre>

<div class="warn">
  <strong>Remember:</strong> Every time you open a new terminal, activate your virtual environment first: <code>source ~/familiar-env/bin/activate</code>
</div>
</div>

<!-- ==================== 7. DASHBOARD ==================== -->
<div class="section" id="s7">
<h2>7. The Web Dashboard &mdash; Your Control Panel</h2>

<p>The dashboard at <code>http://localhost:5000</code> is where most users spend their time. Here's a tour of what you'll find.</p>

<h3>7.1 Dashboard Layout</h3>
<ul>
  <li><strong>Left sidebar</strong> &mdash; Your creature widget (sprite, name, species, stage)</li>
  <li><strong>Center</strong> &mdash; Chat interface &mdash; talk to your Familiar here</li>
  <li><strong>Right sidebar / tabs</strong> &mdash; Status, Memory, Tasks, Email, Nodes, Skills, Messages, Social, Server, Settings</li>
</ul>

<h3>7.2 The Chat Interface</h3>
<p>Type messages in the chat box at the bottom. Your Familiar can:</p>
<ul>
  <li>Answer questions and have conversations</li>
  <li>Execute tasks ("send an email to...", "check my calendar")</li>
  <li>Accept slash commands (type <code>/help</code> to see them all)</li>
</ul>

<h3>7.3 The Settings Card</h3>
<p>Click the Settings tab to customize your creature:</p>
<ul>
  <li><strong>Name</strong> &mdash; rename your familiar (up to 32 characters)</li>
  <li><strong>Species</strong> &mdash; switch between Fox, Owl, Cat, Dragon, Wolf, or Frog</li>
  <li><strong>Stage</strong> &mdash; manually set evolution to Baby, Juvenile, or Adult</li>
  <li><strong>Colors</strong> &mdash; pick body, eye, accent, and voice colors from the palette or enter hex codes</li>
  <li><strong>Save Changes</strong> &mdash; click to persist your choices</li>
  <li><strong>Reset to Baby</strong> &mdash; resets stage and interaction count to start fresh</li>
</ul>

<h3>7.4 Authentication</h3>
<p>By default, the dashboard has no password (it only listens on localhost). To add authentication:</p>
<pre><code>export FAMILIAR_DASHBOARD_KEY="your-secret-key-here"
python -m familiar --dashboard</code></pre>
<p>The dashboard will show a login screen. Enter your key to access it. The key can also be passed as a URL parameter: <code>http://localhost:5000?api_key=your-secret-key-here</code></p>

<h3>7.5 Accessing from Another Device</h3>
<p>By default, the dashboard only accepts connections from localhost. To access it from your phone or another computer on the same network:</p>
<pre><code>python -m familiar.dashboard --host 0.0.0.0</code></pre>
<p>Then open <code>http://&lt;your-computer-ip&gt;:5000</code> from the other device. Always set a <code>FAMILIAR_DASHBOARD_KEY</code> when exposing the dashboard to your network.</p>

<h3>7.6 The Messages Tab</h3>
<p>The Messages tab gives you ICQ-style encrypted peer-to-peer messaging with other Familiar users on your mesh network.</p>
<p><strong>What you'll see:</strong></p>
<ul>
  <li><strong>Left panel</strong> &mdash; Contact list showing all trusted mesh peers with unread message counts</li>
  <li><strong>Right panel</strong> &mdash; Chat area with the selected peer's conversation history</li>
  <li><strong>Unread badge</strong> &mdash; A notification badge appears on the Messages nav item when you have unread messages</li>
</ul>
<p><strong>How to use it:</strong></p>
<ol>
  <li>Click on a peer name in the left panel to open their conversation</li>
  <li>Type your message in the text box at the bottom</li>
  <li>Press Enter or click Send</li>
  <li>Messages are end-to-end encrypted using your mesh encryption keys</li>
  <li>You'll see delivery confirmations (single check) and read receipts (double check)</li>
  <li>Messages are stored locally in an encrypted SQLite database</li>
</ol>
<div class="tip">
  <strong>Requirement:</strong> Both you and the other person must be connected via the mesh network (see Section 15). The peer must have <code>send_messages</code> permission enabled in their trust settings.
</div>

<h3>7.7 The Social Tab</h3>
<p>The Social tab lets you browse and post to your Bluesky and Mastodon accounts from a single unified interface.</p>
<p><strong>Sub-tabs:</strong></p>
<ul>
  <li><strong>Feed</strong> &mdash; A combined, chronological feed from all your connected social platforms. Filter by platform using the filter chips (All / Bluesky / Mastodon). Each post shows the author, avatar, text, likes, reposts, and timestamp. Click "Load More" to fetch older posts.</li>
  <li><strong>Compose</strong> &mdash; Write and cross-post to multiple platforms at once. Check or uncheck platforms to control where your post goes. Character counter shows how much space you have left (300 characters).</li>
  <li><strong>Notifications</strong> &mdash; See likes, reposts, follows, and mentions from all platforms.</li>
</ul>
<p><strong>Setup:</strong> Connect your Bluesky and/or Mastodon accounts first (see Section 14.11). The Social tab automatically appears once at least one platform is configured.</p>
<div class="tip">
  <strong>Polling:</strong> The dashboard checks for new notifications every 10 seconds. An unread badge appears on the Social nav item when you have new notifications.
</div>

<h3>7.8 The Server Tab</h3>
<p>The Server tab lets you provision and manage self-hosted services (like Gitea, Nextcloud, and Jellyfin) directly from your dashboard. No command line needed.</p>
<p><strong>Sub-tabs:</strong></p>
<ul>
  <li><strong>Overview</strong> &mdash; Shows your container runtime (Podman or Docker) and a summary of all services</li>
  <li><strong>Services</strong> &mdash; Individual service cards with status badges and action buttons (Provision, Start, Stop, Restart, Remove)</li>
  <li><strong>Logs</strong> &mdash; View recent log output from any running service</li>
</ul>
<table>
  <tr><th>Service</th><th>What It Does</th><th>Ports</th></tr>
  <tr><td>Email Server</td><td>Self-hosted SMTP email</td><td>(native)</td></tr>
  <tr><td>Gitea (Forgejo)</td><td>Git hosting (like GitHub)</td><td>3000, 2222</td></tr>
  <tr><td>Mealie</td><td>Recipe manager</td><td>9925</td></tr>
  <tr><td>Joplin Server</td><td>Note sync server</td><td>22300</td></tr>
  <tr><td>Pi-hole</td><td>Network ad blocker</td><td>8053, 53</td></tr>
  <tr><td>Nextcloud</td><td>File sync, calendar, contacts</td><td>8080</td></tr>
  <tr><td>Jellyfin</td><td>Media streaming server</td><td>8096</td></tr>
  <tr><td>SearXNG</td><td>Private search engine</td><td>8888</td></tr>
</table>
<p><strong>Requirement:</strong> You need either Podman (preferred) or Docker installed on your machine. The Server tab will show which runtime it detected.</p>
<div class="tip">
  <strong>Job-class recommendations:</strong> During onboarding, Familiar suggests services based on your job class. For example, Chef gets Mealie + Joplin, while Artist gets Gitea + Jellyfin + Nextcloud. All job classes get the email server.
</div>
</div>

<!-- ==================== 8. YOUR CREATURE ==================== -->
<div class="section" id="s8">
<h2>8. Meet Your Creature &mdash; Choosing &amp; Customizing</h2>

<p>Every Familiar has a companion creature &mdash; a pixel-art sprite that represents your AI. The species you choose actually changes how your AI talks and behaves!</p>

<h3>8.1 The Six Species</h3>
<table>
  <tr><th>Species</th><th>Personality</th><th>How It Talks</th><th>Best For</th></tr>
  <tr><td>Fox</td><td>Quick, clever, warm</td><td>Enthusiastic, playful, like a clever friend</td><td>General use (default)</td></tr>
  <tr><td>Owl</td><td>Wise, observant, calm</td><td>Measured, precise, like a trusted advisor</td><td>Research, knowledge work</td></tr>
  <tr><td>Cat</td><td>Independent, graceful</td><td>Dry, understated, gets to the point</td><td>Developers, no-nonsense users</td></tr>
  <tr><td>Dragon</td><td>Powerful, protective</td><td>Bold, confident, like a guardian</td><td>Security-focused, protective</td></tr>
  <tr><td>Wolf</td><td>Pack-minded, reliable</td><td>Steady, team-oriented, uses "we"</td><td>Teams, collaborative work</td></tr>
  <tr><td>Frog</td><td>Adaptable, cheerful</td><td>Upbeat, surprising, makes work lighter</td><td>Fun, creative tasks</td></tr>
</table>

<h3>8.2 Evolution &mdash; Watching Your Creature Grow</h3>
<p>Your creature evolves automatically as you interact with it:</p>
<table>
  <tr><th>Stage</th><th>Triggered At</th><th>What Changes</th></tr>
  <tr><td>Baby</td><td>0 interactions</td><td>Small, simple sprite &mdash; your new companion</td></tr>
  <tr><td>Juvenile</td><td>10+ interactions</td><td>Larger, more detailed sprite with new features</td></tr>
  <tr><td>Adult</td><td>50+ interactions</td><td>Full-sized, elaborate sprite &mdash; fully evolved!</td></tr>
</table>

<h3>8.3 Manual Stage Control</h3>
<p>Don't want to wait? You have full manual control:</p>
<ul>
  <li>Open <strong>Settings</strong> in the dashboard</li>
  <li>Find the <strong>Stage</strong> dropdown (below Species)</li>
  <li>Select <strong>Baby</strong>, <strong>Juvenile</strong>, or <strong>Adult</strong></li>
  <li>The sprite preview updates immediately so you can see the new form</li>
  <li>Click <strong>Save Changes</strong> to keep your choice</li>
  <li>Click <strong>Reset to Baby</strong> to start the evolution journey over (resets interactions to 0)</li>
</ul>

<div class="tip">
  Natural evolution still works in the background. Manual control simply lets you override at any time. Pick any form you like, or reset and grow again from scratch.
</div>

<h3>8.4 Colors</h3>
<p>Customize four color channels for your creature: <strong>Body</strong>, <strong>Eyes</strong>, <strong>Accent</strong>, and <strong>Voice</strong> (highlight color). Choose from 16 named retro palette colors or enter any hex code:</p>
<table>
  <tr><th>Warm</th><th>Cool</th><th>Neutral</th><th>Special</th></tr>
  <tr><td>Crimson, Ember, Gold, Amber</td><td>Emerald, Jade, Sapphire, Cobalt, Violet, Lavender</td><td>Silver, Ivory, Slate, Obsidian</td><td>Rose, Teal</td></tr>
</table>
</div>

<!-- ==================== 9. JOB CLASSES & WORKSPACE ==================== -->
<div class="section" id="s9">
<h2>9. Job Classes &amp; Workspace Panels</h2>

<p>A <strong>Job Class</strong> transforms your Familiar from a generic assistant into a role-specific expert. Each job class tunes the AI's personality, prioritizes relevant skills, and &mdash; most importantly &mdash; gives you a <strong>Workspace Panel</strong> in the dashboard: a dynamic, tabbed workstation tailored to the role.</p>

<h3>9.1 Switching Job Classes</h3>
<p>Change your job class from the dashboard Settings card, or ask your Familiar in chat:</p>
<pre><code>"Switch me to Nonprofit Director"
"Change job class to Chef"
"Go back to Helper mode"</code></pre>

<div class="tip">
  <strong>Workspace appears automatically.</strong> When you switch to a job class that has a workspace, a new nav item appears in the dashboard sidebar. Click it to open your workspace panel.
</div>

<h3>9.2 The Six Job Classes</h3>
<table>
  <tr><th>Job Class</th><th>Icon</th><th>Workspace</th><th>Best For</th></tr>
  <tr><td><strong>Helper</strong></td><td>fa-hat-wizard</td><td>Research Lab</td><td>General research, web browsing, comparisons</td></tr>
  <tr><td><strong>Business Buddy</strong></td><td>fa-briefcase</td><td>Command Center</td><td>Schedule, tasks, email triage</td></tr>
  <tr><td><strong>Social Worker</strong></td><td>fa-hands-holding-heart</td><td>Case Management</td><td>Case tracking, resources, crisis support</td></tr>
  <tr><td><strong>Nonprofit Director</strong></td><td>fa-building-columns</td><td>Nonprofit HQ</td><td>Donors, grants, financials, board prep</td></tr>
  <tr><td><strong>Chef</strong></td><td>fa-utensils</td><td>Kitchen HQ</td><td>Recipes, menus, inventory, food costing</td></tr>
  <tr><td><strong>Artist</strong></td><td>fa-palette</td><td>Studio Manager</td><td>Artwork pipeline, commissions, shows, materials</td></tr>
</table>

<h3>9.3 Workspace Panel Features</h3>
<p>Every workspace panel includes:</p>
<ul>
  <li><strong>Overview cards</strong> &mdash; key metrics at a glance (donor count, YTD revenue, open tasks, etc.)</li>
  <li><strong>Tabbed sections</strong> &mdash; each tab displays data as a <em>table</em>, <em>pipeline</em> (kanban), or <em>summary</em> (stat cards)</li>
  <li><strong>Quick actions</strong> &mdash; role-specific shortcut buttons in the sidebar (replace the default 3 buttons)</li>
  <li><strong>Row actions</strong> &mdash; per-row buttons in tables (e.g. "Details", "Thank You Email") that call tools directly or route through the AI</li>
  <li><strong>Sorting &amp; pagination</strong> &mdash; click column headers to sort; large datasets paginate automatically</li>
</ul>

<h3>9.4 Nonprofit Director &mdash; Nonprofit HQ</h3>
<p>A full nonprofit back-office workstation.</p>
<table>
  <tr><th>Tab</th><th>Type</th><th>What It Shows</th></tr>
  <tr><td>Donors</td><td>Table</td><td>Name, email, total given, last gift date, interactions. Row actions: Details, Thank You email.</td></tr>
  <tr><td>Grant Pipeline</td><td>Pipeline</td><td>Kanban board: Prospect &rarr; Applied &rarr; Awarded &rarr; Declined &rarr; Completed. Cards show funder and amount.</td></tr>
  <tr><td>Financials</td><td>Summary</td><td>YTD income, expenses, net position, donor revenue, grant revenue, transaction count.</td></tr>
  <tr><td>Notes</td><td>Table</td><td>Date, category (badge), content.</td></tr>
</table>
<p><strong>Quick actions:</strong> Log Donation, Board Packet, 990 Export, Who Needs Thanks, Grant Deadlines, Quick Note.</p>

<h3>9.5 Business Buddy &mdash; Command Center</h3>
<table>
  <tr><th>Tab</th><th>Type</th><th>What It Shows</th></tr>
  <tr><td>Today</td><td>Table</td><td>Today's calendar events with time, event name, location, attendee count.</td></tr>
  <tr><td>Tasks</td><td>Table</td><td>Open tasks by priority (badge), due date, category. Row action: Complete.</td></tr>
  <tr><td>Email</td><td>Summary</td><td>Urgent count, Need Action, FYI, Total Unread.</td></tr>
</table>
<p><strong>Quick actions:</strong> Morning Briefing, Sort Inbox, Check Deadlines, Add Task.</p>

<h3>9.6 Social Worker &mdash; Case Management</h3>
<table>
  <tr><th>Tab</th><th>Type</th><th>What It Shows</th></tr>
  <tr><td>Cases</td><td>Pipeline</td><td>Kanban: Intake &rarr; Assessment &rarr; Active &rarr; Follow-Up &rarr; Closed.</td></tr>
  <tr><td>Resources</td><td>Table</td><td>Community resource directory with name, type, phone, address, notes.</td></tr>
  <tr><td>Notes</td><td>Table</td><td>Case notes by date, case, and type.</td></tr>
  <tr><td>Crisis Log</td><td>Table</td><td>Crisis events with severity, summary, and outcome.</td></tr>
</table>
<p><strong>Quick actions:</strong> New Case, Find Resources, Case Note, Crisis Hotlines, Check Follow-Ups, Safety Plan.</p>

<h3>9.7 Chef &mdash; Kitchen HQ</h3>
<table>
  <tr><th>Tab</th><th>Type</th><th>What It Shows</th></tr>
  <tr><td>Recipes</td><td>Table</td><td>Recipe name, cuisine, servings, prep time, cost per serving.</td></tr>
  <tr><td>Menus</td><td>Table</td><td>Menu name, item count, average plate cost, status.</td></tr>
  <tr><td>Vendors</td><td>Table</td><td>Supplier name, category, phone, email, order schedule.</td></tr>
  <tr><td>Inventory</td><td>Table</td><td>Ingredient, quantity, unit, par level, reorder status.</td></tr>
  <tr><td>Schedule</td><td>Table</td><td>Staff name, role, shift date, hours.</td></tr>
  <tr><td>Cost Tracker</td><td>Summary</td><td>Food cost %, labor cost %, revenue MTD, average plate cost.</td></tr>
</table>
<p><strong>Quick actions:</strong> Add Recipe, Create Menu, Log Cost, Add Vendor, Prep List, Weekly Report.</p>

<h3>9.8 Artist &mdash; Studio Manager</h3>
<table>
  <tr><th>Tab</th><th>Type</th><th>What It Shows</th></tr>
  <tr><td>Pieces</td><td>Pipeline</td><td>Artwork lifecycle: Concept &rarr; In Progress &rarr; Drying &rarr; Bisque Fire &rarr; Glazing &rarr; Glaze Fire &rarr; Finished &rarr; Listed &rarr; Sold.</td></tr>
  <tr><td>Commissions</td><td>Table</td><td>Client, description, price, deposit paid, due date, status.</td></tr>
  <tr><td>Shows &amp; Events</td><td>Table</td><td>Show name, venue, dates, piece count, status.</td></tr>
  <tr><td>Materials</td><td>Table</td><td>Supply name, quantity, unit, reorder point, supplier.</td></tr>
  <tr><td>Clients</td><td>Table</td><td>Collector name, email, total spent, last purchase, notes.</td></tr>
</table>
<p><strong>Quick actions:</strong> Log New Piece, New Commission, Add Show, Material Order, Price Calculator, Kiln Log.</p>

<h3>9.9 Helper &mdash; Research Lab</h3>
<table>
  <tr><th>Tab</th><th>Type</th><th>What It Shows</th></tr>
  <tr><td>Searches</td><td>Table</td><td>Saved search queries with date, engine, result count.</td></tr>
  <tr><td>Bookmarks</td><td>Table</td><td>Saved URLs with title, domain, tags, date added.</td></tr>
  <tr><td>Comparisons</td><td>Table</td><td>Product/option comparison results.</td></tr>
  <tr><td>Tracked Topics</td><td>Table</td><td>Monitored topics with last check date and update count.</td></tr>
</table>
<p><strong>Quick actions:</strong> Web Search, Compare Products, Summarize Page, Follow Topic, Browse Site, What's Trending.</p>

<div class="tip">
  <strong>Custom job classes via the Marketplace.</strong> You can install community-created job classes that add entirely new workspace panels. See Section 18 (Marketplace) for details.
</div>
</div>

<!-- ==================== 10. CHAT COMMANDS ==================== -->
<div class="section" id="s10">
<h2>10. Talking to Your Familiar &mdash; Chat Commands</h2>

<p>Besides normal conversation, your Familiar understands special commands that start with <code>/</code>. Type these in the chat box (dashboard) or terminal (CLI).</p>

<h3>10.1 Essential Commands (Start Here)</h3>
<table>
  <tr><th>Command</th><th>What It Does</th><th>Example</th></tr>
  <tr><td><code>/help</code></td><td>Shows all available commands</td><td><code>/help</code></td></tr>
  <tr><td><code>/start</code></td><td>Runs the tarot onboarding spread</td><td><code>/start</code></td></tr>
  <tr><td><code>/status</code></td><td>Shows system info (model, memory, skills)</td><td><code>/status</code></td></tr>
  <tr><td><code>/clear</code></td><td>Clears conversation history</td><td><code>/clear</code></td></tr>
  <tr><td><code>/model</code></td><td>Shows which AI model is active</td><td><code>/model</code></td></tr>
  <tr><td><code>/model claude</code></td><td>Switches to Claude</td><td><code>/model ollama</code></td></tr>
</table>

<h3>10.2 Memory Commands</h3>
<table>
  <tr><th>Command</th><th>What It Does</th></tr>
  <tr><td><code>/remember &lt;key&gt; &lt;value&gt;</code></td><td>Save a fact. E.g.: <code>/remember birthday March 15</code></td></tr>
  <tr><td><code>/recall &lt;query&gt;</code></td><td>Search memories. E.g.: <code>/recall birthday</code></td></tr>
</table>

<h3>10.3 Trust &amp; Budget Commands</h3>
<table>
  <tr><th>Command</th><th>What It Does</th></tr>
  <tr><td><code>/trust</code></td><td>Shows your trust level and progression</td></tr>
  <tr><td><code>/budget</code></td><td>Shows daily spending status</td></tr>
  <tr><td><code>/caps</code></td><td>Shows what capabilities are granted</td></tr>
</table>

<h3>10.4 Connection Commands</h3>
<table>
  <tr><th>Command</th><th>What It Does</th></tr>
  <tr><td><code>/connect</code></td><td>Opens the service connection wizard (main menu)</td></tr>
  <tr><td><code>/connect email</code></td><td>Set up email integration</td></tr>
  <tr><td><code>/connect ollama</code></td><td>Manage local Ollama models</td></tr>
  <tr><td><code>/browse</code></td><td>Browse data from connected services</td></tr>
  <tr><td><code>/search &lt;service&gt; &lt;query&gt;</code></td><td>Search a connected service</td></tr>
</table>

<h3>10.5 CLI-Only Commands</h3>
<table>
  <tr><th>Command</th><th>What It Does</th></tr>
  <tr><td><code>/quit</code> or <code>/exit</code></td><td>Exit the CLI</td></tr>
  <tr><td><code>/models</code></td><td>List all available LLM providers</td></tr>
  <tr><td><code>/skills</code></td><td>List all loaded skills</td></tr>
  <tr><td><code>/tools</code></td><td>List all registered tools</td></tr>
  <tr><td><code>/creature</code></td><td>Show creature stats</td></tr>
</table>
</div>

<!-- ==================== 11. CHANNELS ==================== -->
<div class="section" id="s11">
<h2>11. Connecting Channels (Telegram, Discord, etc.)</h2>

<p>Familiar can talk to you through many different platforms. The easiest way to set them up is the <code>/connect</code> wizard.</p>

<h3>11.1 Available Channels</h3>
<table>
  <tr><th>Channel</th><th>Setup Difficulty</th><th>Best For</th></tr>
  <tr><td>CLI (terminal)</td><td>Built-in</td><td>Quick tasks, developers</td></tr>
  <tr><td>Web Dashboard</td><td>Built-in</td><td>Daily use, visual interface</td></tr>
  <tr><td>Telegram</td><td>Easy (5 min)</td><td>Mobile messaging, most popular</td></tr>
  <tr><td>Discord</td><td>Easy (10 min)</td><td>Teams, communities</td></tr>
  <tr><td>Matrix</td><td>Medium</td><td>Privacy-focused, E2EE</td></tr>
  <tr><td>Slack</td><td>Medium</td><td>Workplace integration</td></tr>
  <tr><td>GitHub</td><td>Easy</td><td>Development workflow</td></tr>
  <tr><td>Microsoft Teams</td><td>Medium</td><td>Enterprise environments</td></tr>
  <tr><td>Signal / iMessage / WhatsApp / SMS</td><td>Advanced</td><td>Personal messaging</td></tr>
  <tr><td>Bluesky</td><td>Easy (5 min)</td><td>Decentralized social media</td></tr>
  <tr><td>Mastodon</td><td>Easy (5 min)</td><td>Federated social media</td></tr>
</table>

<h3>11.2 Setting Up Telegram (Example Walkthrough)</h3>
<div class="step">
  <span class="step-num">1</span> Open Telegram and search for <strong>@BotFather</strong><br>
  <span class="step-num">2</span> Send <code>/newbot</code> and follow the prompts to create a bot<br>
  <span class="step-num">3</span> BotFather gives you a token like <code>123456:ABC-DEF...</code> &mdash; copy it<br>
  <span class="step-num">4</span> Set the token: <code>export TELEGRAM_BOT_TOKEN="123456:ABC-DEF..."</code><br>
  <span class="step-num">5</span> Start Familiar with Telegram: <code>python -m familiar --telegram --dashboard</code><br>
  <span class="step-num">6</span> Find your bot in Telegram and send it a message!
</div>

<h3>11.3 Using the Connect Wizard</h3>
<p>For any channel, you can use the interactive wizard. Type <code>/connect</code> in the chat and follow the prompts. The wizard handles token creation, permissions, and sends test messages to verify everything works.</p>

<table>
  <tr><th>Wizard Command</th><th>What It Sets Up</th></tr>
  <tr><td><code>/connect email</code></td><td>Email (Gmail, Outlook, Yahoo, Proton, Custom)</td></tr>
  <tr><td><code>/connect calendar</code></td><td>Calendar (Google, CalDAV)</td></tr>
  <tr><td><code>/connect ollama</code></td><td>Local AI model management</td></tr>
  <tr><td><code>/connect github</code></td><td>GitHub integration</td></tr>
  <tr><td><code>/connect slack</code></td><td>Slack integration</td></tr>
  <tr><td><code>/connect jellyfin</code></td><td>Jellyfin media server</td></tr>
  <tr><td><code>/connect nextcloud</code></td><td>Nextcloud file/calendar sync</td></tr>
  <tr><td><code>/connect homeassistant</code></td><td>Home Assistant smart home</td></tr>
  <tr><td><code>/connect security</code></td><td>Encryption, RBAC, Vaultwarden</td></tr>
  <tr><td><code>/connect status</code></td><td>Shows all connection statuses</td></tr>
</table>
</div>

<!-- ==================== 12. LLM PROVIDERS ==================== -->
<div class="section" id="s12">
<h2>12. Choosing Your AI Brain &mdash; LLM Providers</h2>

<h3>12.1 Cloud Providers</h3>
<table>
  <tr><th>Provider</th><th>Default Model</th><th>Context Window</th><th>Best For</th></tr>
  <tr><td>Anthropic</td><td>claude-sonnet-4-6</td><td>200K tokens</td><td>Best reasoning, safety</td></tr>
  <tr><td>OpenAI</td><td>gpt-4o</td><td>128K tokens</td><td>Well-rounded, fast</td></tr>
  <tr><td>Google Gemini</td><td>gemini-2.5-flash</td><td>1M tokens</td><td>Largest context, free tier</td></tr>
</table>

<h3>12.2 Local Models via Ollama</h3>
<p>These run entirely on your machine &mdash; no internet needed, 100% private.</p>
<table>
  <tr><th>Model</th><th>RAM Needed</th><th>Speed</th><th>Quality</th></tr>
  <tr><td>llama3.2 (default)</td><td>~4 GB</td><td>Fast</td><td>Very good</td></tr>
  <tr><td>qwen3.5:27b</td><td>~16 GB</td><td>Medium</td><td>Excellent</td></tr>
  <tr><td>deepseek-r1:14b</td><td>~8 GB</td><td>Medium</td><td>Great reasoning</td></tr>
  <tr><td>mistral</td><td>~4 GB</td><td>Fast</td><td>Good</td></tr>
  <tr><td>phi3:mini</td><td>~2 GB</td><td>Very fast</td><td>Basic tasks</td></tr>
  <tr><td>tinyllama</td><td>~1 GB</td><td>Instant</td><td>Simple tasks only</td></tr>
</table>

<h3>12.3 Switching Models On the Fly</h3>
<p>You can switch providers at any time, even mid-conversation:</p>
<pre><code>/model claude      # Switch to Claude
/model ollama      # Switch to local Ollama
/model gpt         # Switch to GPT-4o
/model gemini      # Switch to Gemini</code></pre>

<h3>12.4 Managing Ollama Models</h3>
<pre><code>/connect ollama              # Open Ollama management wizard
/connect ollama list         # See installed models
/connect ollama pull qwen3.5:27b  # Download a new model
/connect ollama remove mistral    # Delete a model
/connect ollama test         # Test connectivity</code></pre>
</div>

<!-- ==================== 13. SKILLS ==================== -->
<div class="section" id="s13">
<h2>13. Skills &mdash; What Your Familiar Can Do</h2>

<p>Skills are modules that give your Familiar specific abilities. 80+ built-in skills are included and automatically loaded based on your installed extras and connected services.</p>

<table>
  <tr><th>Category</th><th>Skills</th><th>What You Can Ask</th></tr>
  <tr><td>Communication</td><td>email, triage, messaging, sms, notifications, meetings, voice, transcription</td><td>"Send an email to...", "Text John...", "Read this aloud"</td></tr>
  <tr><td>Productivity</td><td>calendar, calcom, tasks, todoist, planner, proactive, triggers, workflows</td><td>"Schedule a meeting", "What's on my calendar?", "Add a task"</td></tr>
  <tr><td>Knowledge &amp; Search</td><td>knowledge, knowledge_base, websearch, brave_search, smart_search, services</td><td>"Search for...", "Find articles about..."</td></tr>
  <tr><td>Documents &amp; Files</td><td>filereader, documents, gdrive, browser, private_browser, webapi, charts, presentations</td><td>"Summarize this PDF", "Open this URL", "Create a chart", "Make a presentation"</td></tr>
  <tr><td>Nonprofit &amp; CRM</td><td>nonprofit, contacts, bookkeeping, reports, civicrm, hubspot, mailerlite, globalgiving</td><td>"Log a donation", "Show donor history"</td></tr>
  <tr><td>Finance &amp; Commerce</td><td>stripe_pay, square, quickbooks, etsy, shippo, clockify</td><td>"Create an invoice", "Track my time", "Ship this order"</td></tr>
  <tr><td>Self-Hosted</td><td>nextcloud, gitea, jellyfin, pihole, homeassistant, joplin, mealie, vaultwarden, proton</td><td>"Play a movie", "Turn off the lights", "Show my notes"</td></tr>
  <tr><td>Healthcare &amp; Social</td><td>hrsa, npi, samhsa, open_referral, kobo, phi_detection</td><td>"Find a health center near...", "Search for treatment facilities"</td></tr>
  <tr><td>Food &amp; Recipes</td><td>fooddata, spoonacular, mealie, openfoodfacts</td><td>"Find a recipe for...", "Nutrition info for..."</td></tr>
  <tr><td>Social &amp; Media</td><td>reddit, instagram, google_trends, news, video, cloudinary_img, bluesky, mastodon</td><td>"What's trending?", "Show recent posts", "Post to Bluesky"</td></tr>
  <tr><td>Grants &amp; Research</td><td>grants_gov, globalgiving, propublica_nonprofit</td><td>"Search for grants", "Look up a nonprofit's 990"</td></tr>
  <tr><td>Security &amp; Compliance</td><td>rbac, sessions, encryption, audit, compliance, user_management</td><td>"Show audit log", "Encrypt my data"</td></tr>
</table>

<p>View your loaded skills anytime: type <code>/skills</code> in the CLI or check the Skills tab in the dashboard.</p>

<div class="tip">
  <strong>Skills load automatically</strong> when you install the relevant extras or set the required environment variables. For example, installing <code>familiar-agent[web]</code> enables browser and websearch skills. Setting <code>STRIPE_SECRET_KEY</code> enables payment processing.
</div>

<h3>13.1 Office Suite &mdash; Documents, Charts &amp; Presentations</h3>
<p>Familiar includes a full office suite for creating professional documents:</p>
<p><strong>Bundled Templates (27 templates)</strong></p>
<p>Each job class comes with ready-made document templates:</p>
<table>
  <tr><th>Job Class</th><th>Templates</th></tr>
  <tr><td>Helper</td><td>Meeting Notes, Research Summary, Comparison Report</td></tr>
  <tr><td>Social Worker</td><td>Case Assessment, Safety Plan, Resource Guide, Progress Note</td></tr>
  <tr><td>Business Buddy</td><td>Invoice, Expense Report, Weekly Status, Project Brief</td></tr>
  <tr><td>Nonprofit Director</td><td>Grant Application, Board Report, Donor Letter, Annual Report, Budget</td></tr>
  <tr><td>Chef</td><td>Recipe Card, Menu, Prep Sheet, Cost Analysis, Inventory Report</td></tr>
  <tr><td>Artist</td><td>Commission Agreement, Exhibition Proposal, Price List, Portfolio Summary, Artist Statement, Materials Log</td></tr>
</table>
<p>Your own templates in <code>~/.familiar/templates/</code> override the bundled ones.</p>
<p><strong>Charts</strong></p>
<p>Ask your Familiar to create charts:</p>
<pre><code>"Create a bar chart of monthly sales"
"Make a pie chart showing expense categories"
"Generate a line chart of website traffic over time"</code></pre>
<p>Supported chart types: bar, pie, line, and horizontal bar. Charts can also be embedded directly into Word documents and PowerPoint presentations.</p>
<p><strong>Presentations</strong></p>
<p>Create PowerPoint-style presentations with multiple slide types:</p>
<pre><code>"Create a presentation about Q1 results"
"Make a pitch deck for our startup"
"Generate a meeting summary presentation"</code></pre>
<p>Slide types: title, content, table, chart, and section divider. Three built-in layouts: report, pitch, and meeting.</p>
<div class="tip">
  <strong>Dependencies:</strong> Charts require <code>matplotlib</code> and presentations require <code>python-pptx</code>. Install both with: <code>pip install familiar-agent[docs]</code>
</div>
</div>

<!-- ==================== 14. API INTEGRATIONS ==================== -->
<div class="section" id="s14">
<h2>14. API Integrations &amp; Service Setup</h2>

<p>Many skills connect to external services via API keys. This section shows you how to set up each integration. Set environment variables in your <code>~/.familiar/.env</code> file or export them in your shell.</p>

<h3>14.1 CRM &amp; Marketing</h3>
<table>
  <tr><th>Service</th><th>Env Vars</th><th>How to Get Keys</th></tr>
  <tr><td><strong>HubSpot</strong></td><td><code>HUBSPOT_ACCESS_TOKEN</code></td><td>HubSpot &rarr; Settings &rarr; Integrations &rarr; Private Apps &rarr; Create. Scopes: <code>crm.objects.contacts.read</code>, <code>crm.objects.deals.read</code>.</td></tr>
  <tr><td><strong>CiviCRM</strong></td><td><code>CIVICRM_URL</code>, <code>CIVICRM_API_KEY</code>, <code>CIVICRM_SITE_KEY</code></td><td>Self-hosted. API key from user profile; site key from <code>civicrm.settings.php</code>.</td></tr>
  <tr><td><strong>MailerLite</strong></td><td><code>MAILERLITE_API_KEY</code></td><td>MailerLite &rarr; Integrations &rarr; API &rarr; Generate key.</td></tr>
</table>

<h3>14.2 Payments &amp; Finance</h3>
<table>
  <tr><th>Service</th><th>Env Vars</th><th>How to Get Keys</th></tr>
  <tr><td><strong>Stripe</strong></td><td><code>STRIPE_SECRET_KEY</code></td><td>Stripe Dashboard &rarr; Developers &rarr; API keys. Use test key (<code>sk_test_</code>) first.</td></tr>
  <tr><td><strong>Square</strong></td><td><code>SQUARE_ACCESS_TOKEN</code></td><td>Square Developer &rarr; Applications &rarr; Credentials.</td></tr>
  <tr><td><strong>QuickBooks</strong></td><td><code>QUICKBOOKS_ACCESS_TOKEN</code>, <code>QUICKBOOKS_REALM_ID</code></td><td>Intuit Developer &rarr; Create app &rarr; OAuth 2.0 flow. Realm ID is your company ID.</td></tr>
</table>

<h3>14.3 Tasks &amp; Time Tracking</h3>
<table>
  <tr><th>Service</th><th>Env Vars</th><th>How to Get Keys</th></tr>
  <tr><td><strong>Todoist</strong></td><td><code>TODOIST_API_TOKEN</code></td><td>Todoist &rarr; Settings &rarr; Integrations &rarr; Developer &rarr; API token.</td></tr>
  <tr><td><strong>Clockify</strong></td><td><code>CLOCKIFY_API_KEY</code>, <code>CLOCKIFY_WORKSPACE_ID</code></td><td>Clockify &rarr; Profile Settings &rarr; API &rarr; Generate key. Workspace ID from URL.</td></tr>
  <tr><td><strong>Cal.com</strong></td><td><code>CALCOM_API_KEY</code></td><td>Cal.com &rarr; Settings &rarr; Developer &rarr; API Keys. Works with self-hosted instances too.</td></tr>
</table>

<h3>14.4 E-Commerce &amp; Shipping</h3>
<table>
  <tr><th>Service</th><th>Env Vars</th><th>How to Get Keys</th></tr>
  <tr><td><strong>Etsy</strong></td><td><code>ETSY_API_KEY</code>, <code>ETSY_SHOP_ID</code></td><td>Etsy Developers &rarr; Create app &rarr; API key. Shop ID from your shop URL.</td></tr>
  <tr><td><strong>Shippo</strong></td><td><code>SHIPPO_API_KEY</code></td><td>Shippo Dashboard &rarr; API &rarr; Token. Supports USPS, UPS, FedEx, DHL.</td></tr>
  <tr><td><strong>Cloudinary</strong></td><td><code>CLOUDINARY_CLOUD_NAME</code>, <code>CLOUDINARY_API_KEY</code></td><td>Cloudinary Dashboard &rarr; Account Details.</td></tr>
</table>

<h3>14.5 Social &amp; Content</h3>
<table>
  <tr><th>Service</th><th>Env Vars</th><th>How to Get Keys</th></tr>
  <tr><td><strong>Reddit</strong></td><td><code>REDDIT_CLIENT_ID</code>, <code>REDDIT_CLIENT_SECRET</code></td><td>reddit.com/prefs/apps &rarr; Create app (type: script).</td></tr>
  <tr><td><strong>Instagram</strong></td><td><code>INSTAGRAM_ACCESS_TOKEN</code>, <code>INSTAGRAM_BUSINESS_ID</code></td><td>Meta for Developers &rarr; Create app &rarr; Instagram Graph API. Requires a business/creator account.</td></tr>
  <tr><td><strong>Google Trends</strong></td><td><code>GOOGLE_TRENDS_API_KEY</code></td><td>SerpApi or similar proxy. Direct Google Trends has no official API.</td></tr>
</table>

<h3>14.6 Search &amp; News</h3>
<table>
  <tr><th>Service</th><th>Env Vars</th><th>How to Get Keys</th></tr>
  <tr><td><strong>Brave Search</strong></td><td><code>BRAVE_SEARCH_API_KEY</code></td><td>brave.com/search/api &rarr; Sign up &rarr; Free tier: 2K queries/month.</td></tr>
  <tr><td><strong>GNews</strong></td><td><code>GNEWS_API_KEY</code></td><td>gnews.io &rarr; Sign up &rarr; Free tier: 100 requests/day.</td></tr>
  <tr><td><strong>Newsdata.io</strong></td><td><code>NEWSDATA_API_KEY</code></td><td>newsdata.io &rarr; Sign up &rarr; Free tier: 200 credits/day.</td></tr>
</table>

<h3>14.7 Healthcare &amp; Social Services</h3>
<table>
  <tr><th>Service</th><th>Env Vars</th><th>Notes</th></tr>
  <tr><td><strong>Open Referral (211)</strong></td><td><code>OPEN_REFERRAL_URL</code></td><td>Point to any HSDS-compatible endpoint (e.g. local 211 directory).</td></tr>
  <tr><td><strong>KoboToolbox</strong></td><td><code>KOBO_URL</code>, <code>KOBO_TOKEN</code></td><td>kf.kobotoolbox.org &rarr; Account Settings &rarr; API Token.</td></tr>
  <tr><td><strong>HRSA, NPI, SAMHSA</strong></td><td>None required</td><td>Free public APIs. HRSA health centers, NPI provider lookup, SAMHSA treatment facilities.</td></tr>
</table>

<h3>14.8 Grants &amp; Nonprofit Research</h3>
<table>
  <tr><th>Service</th><th>Env Vars</th><th>Notes</th></tr>
  <tr><td><strong>Grants.gov</strong></td><td><code>GRANTS_GOV_API_KEY</code> (optional)</td><td>Free API. Key gives higher rate limits.</td></tr>
  <tr><td><strong>GlobalGiving</strong></td><td><code>GLOBALGIVING_API_KEY</code></td><td>globalgiving.org/api &rarr; Apply for key.</td></tr>
  <tr><td><strong>ProPublica Nonprofit</strong></td><td>None required</td><td>Free. Search 990 filings and nonprofit data.</td></tr>
</table>

<h3>14.9 Food &amp; Recipe</h3>
<table>
  <tr><th>Service</th><th>Env Vars</th><th>Notes</th></tr>
  <tr><td><strong>Spoonacular</strong></td><td><code>SPOONACULAR_API_KEY</code></td><td>spoonacular.com/food-api &rarr; Sign up. Free tier: 150 requests/day.</td></tr>
  <tr><td><strong>FoodData Central</strong></td><td><code>FOODDATA_API_KEY</code> (optional)</td><td>fdc.nal.usda.gov &rarr; Get API key. Works with demo key for basic use.</td></tr>
  <tr><td><strong>Mealie</strong></td><td><code>MEALIE_URL</code>, <code>MEALIE_TOKEN</code></td><td>Self-hosted recipe manager. Token from user profile.</td></tr>
  <tr><td><strong>Open Food Facts</strong></td><td>None required</td><td>Free open database. Barcode lookup, allergen checking.</td></tr>
</table>

<h3>14.10 Meetings &amp; Video</h3>
<table>
  <tr><th>Service</th><th>Env Vars</th><th>Notes</th></tr>
  <tr><td><strong>Jitsi</strong></td><td><code>JITSI_URL</code></td><td>Default: meet.jit.si (free). Set URL for self-hosted instances.</td></tr>
</table>

<h3>14.11 Social Media Platforms</h3>
<table>
  <tr><th>Service</th><th>Env Vars</th><th>How to Get Keys</th></tr>
  <tr><td><strong>Bluesky</strong></td><td><code>BLUESKY_HANDLE</code>, <code>BLUESKY_APP_PASSWORD</code></td><td>Go to bsky.app &rarr; Settings &rarr; App Passwords &rarr; Add App Password. Your handle is your username (e.g. <code>yourname.bsky.social</code>).</td></tr>
  <tr><td><strong>Mastodon</strong></td><td><code>MASTODON_INSTANCE_URL</code>, <code>MASTODON_ACCESS_TOKEN</code></td><td>On your Mastodon instance &rarr; Preferences &rarr; Development &rarr; New Application. Grant read and write scopes. Copy the access token.</td></tr>
</table>

<p><strong>Bluesky setup:</strong></p>
<div class="step">
  <span class="step-num">1</span> Log in to <strong>bsky.app</strong> in your browser<br>
  <span class="step-num">2</span> Go to <strong>Settings &rarr; App Passwords</strong><br>
  <span class="step-num">3</span> Click <strong>"Add App Password"</strong> and give it a name like "familiar"<br>
  <span class="step-num">4</span> Copy the generated password<br>
  <span class="step-num">5</span> Set the environment variables:<br>
  <pre><code>export BLUESKY_HANDLE="yourname.bsky.social"
export BLUESKY_APP_PASSWORD="xxxx-xxxx-xxxx-xxxx"</code></pre>
</div>

<p><strong>Mastodon setup:</strong></p>
<div class="step">
  <span class="step-num">1</span> Log in to your Mastodon instance (e.g. mastodon.social)<br>
  <span class="step-num">2</span> Go to <strong>Preferences &rarr; Development &rarr; New Application</strong><br>
  <span class="step-num">3</span> Give it a name like "Familiar"<br>
  <span class="step-num">4</span> Check <strong>read</strong> and <strong>write</strong> scopes<br>
  <span class="step-num">5</span> Click <strong>Submit</strong>, then click on your new app<br>
  <span class="step-num">6</span> Copy the <strong>Access Token</strong><br>
  <span class="step-num">7</span> Set the environment variables:<br>
  <pre><code>export MASTODON_INSTANCE_URL="https://mastodon.social"
export MASTODON_ACCESS_TOKEN="your-access-token"</code></pre>
</div>

<div class="tip">
  <strong>Quick setup:</strong> Use the <code>/connect</code> wizard to configure most integrations interactively. The wizard tests connectivity and saves credentials to <code>~/.familiar/.env</code>.
</div>
</div>

<!-- ==================== 15. MESH ==================== -->
<div class="section" id="s15">
<h2>15. Multi-Device Mesh Networking</h2>

<p>Connect multiple Familiar instances across devices into an encrypted network. Your desktop Familiar can delegate tasks to a Raspberry Pi Familiar, for example.</p>

<h3>15.0 Setting Up a Mesh</h3>
<div class="step">
  <span class="step-num">1</span> Install the mesh extra on all devices: <code>pip install familiar-agent[mesh]</code><br>
  <span class="step-num">2</span> On the main device (gateway): <code>familiar-mesh gateway --public --discovery</code><br>
  <span class="step-num">3</span> Note the secret key: <code>familiar-mesh status</code><br>
  <span class="step-num">4</span> On other devices: <code>familiar-mesh node ws://gateway-ip:18789 --key YOUR_KEY</code><br>
  <span class="step-num">5</span> Check the Nodes tab in the dashboard to see connected devices
</div>

<ul>
  <li>All communication is <strong>NaCl-encrypted</strong></li>
  <li><strong>Zeroconf</strong> auto-discovers peers on the same LAN</li>
  <li>Nodes share skills, memory queries, and task delegation</li>
</ul>

<h3>15.1 Memory Sharing</h3>
<p>Mesh peers can share markdown memories with each other. This lets multiple Familiar instances build on each other's knowledge.</p>
<p><strong>How it works:</strong></p>
<ul>
  <li>Memories are pushed/pulled between peers as markdown files</li>
  <li>Content is verified using SHA-256 hashes to prevent tampering</li>
  <li>Each peer controls what they share via the <code>share_markdown_memories</code> permission</li>
</ul>
<p><strong>Enable memory sharing:</strong></p>
<pre><code># In chat, grant a peer memory sharing permission:
"Allow memory sharing with &lt;peer-name&gt;"</code></pre>
<p>Shared memories appear in your Familiar's context automatically when relevant to a conversation.</p>

<h3>15.2 Model Sharing</h3>
<p>Peers on your mesh can share Ollama models with each other, saving bandwidth and download time.</p>
<p><strong>How it works:</strong></p>
<ul>
  <li>Peers exchange model catalogs so you can see what models are available on the network</li>
  <li>Models are transferred in 256 KB chunks with SHA-256 verification</li>
  <li>You can also delegate inference to a peer that has a larger model</li>
</ul>
<p><strong>Enable model sharing:</strong></p>
<pre><code># Grant model sharing permission:
"Allow model sharing with &lt;peer-name&gt;"</code></pre>
<p>Model packages (<code>.familiar-model</code> files) are auto-scanned and registered in the mesh catalog.</p>

<h3>15.3 Peer Messaging</h3>
<p>Send encrypted, ICQ-style 1:1 messages to other Familiar users on your mesh. See Section 7.6 (The Messages Tab) for the dashboard interface.</p>
<p><strong>Features:</strong></p>
<ul>
  <li>End-to-end encrypted using your mesh Signal Protocol keys</li>
  <li>Delivery receipts (message received) and read receipts (message seen)</li>
  <li>Typing indicators (visible for up to 5 seconds)</li>
  <li>Offline queue &mdash; messages sent while a peer is offline are stored and delivered when they reconnect (up to 10 retry attempts)</li>
  <li>Messages stored locally in SQLite at <code>~/.familiar/data/mesh/messages.db</code></li>
</ul>
<div class="tip">
  <strong>Permission:</strong> Both peers must have <code>send_messages</code> enabled in their trust settings.
</div>

<h3>15.4 Usage Tracking &amp; Dross Tokens</h3>
<p>The mesh tracks resource usage across peers with a built-in micro-economy:</p>
<table>
  <tr><th>Action</th><th>Dross Multiplier</th></tr>
  <tr><td>Memory query</td><td>0.1</td></tr>
  <tr><td>Memory push (used)</td><td>0.5</td></tr>
  <tr><td>Markdown pull</td><td>0.3</td></tr>
  <tr><td>Model inference (delegated)</td><td>1.0</td></tr>
  <tr><td>Model download</td><td>5.0</td></tr>
</table>
<p>Usage records are stored in SQLite and can be anchored to the on-chain ledger for transparency. Dross tokens are minted based on usage to create a fair exchange economy between peers.</p>
</div>

<!-- ==================== 16. SERVER PROVISIONING ==================== -->
<div class="section" id="s16">
<h2>16. Self-Hosted Server Provisioning</h2>

<p>Familiar can provision and manage self-hosted services on your machine using container technology. This lets you run your own private alternatives to cloud services.</p>

<h3>16.1 Requirements</h3>
<p>You need a container runtime installed:</p>
<ul>
  <li><strong>Podman</strong> (preferred) &mdash; rootless containers, no daemon needed</li>
  <li><strong>Docker</strong> &mdash; also supported as a fallback</li>
</ul>
<p>The Server tab in the dashboard will auto-detect which runtime you have.</p>

<h3>16.2 Provisioning a Service</h3>
<p><strong>From the dashboard:</strong></p>
<ol>
  <li>Open the <strong>Server</strong> tab</li>
  <li>Click <strong>Provision</strong> on any service card</li>
  <li>Wait for the container image to download (first time only)</li>
  <li>Click <strong>Start</strong> to launch the service</li>
  <li>Access the service at <code>http://localhost:&lt;port&gt;</code> (see port table in Section 7.8)</li>
</ol>
<p><strong>From chat:</strong></p>
<pre><code>"Set up Gitea for me"
"Provision Nextcloud"
"Start the Mealie recipe server"</code></pre>

<h3>16.3 Managing Services</h3>
<p>All services can be managed from the Server tab or through chat:</p>
<ul>
  <li><strong>Start</strong> &mdash; Launch a provisioned service</li>
  <li><strong>Stop</strong> &mdash; Shut down a running service (data is preserved)</li>
  <li><strong>Restart</strong> &mdash; Stop and start a service</li>
  <li><strong>Remove</strong> &mdash; Delete the container (optionally remove data too)</li>
  <li><strong>Logs</strong> &mdash; View recent log output for debugging</li>
</ul>
<p>Service state is persisted at <code>~/.familiar/services/state.json</code>. Container data volumes are stored under <code>~/.familiar/services/&lt;service-key&gt;/</code>.</p>

<h3>16.4 Docker Compose Export</h3>
<p>If you prefer managing services with docker-compose or podman-compose:</p>
<pre><code>"Generate a compose file for my services"</code></pre>
<p>This creates a <code>familiar-compose.yml</code> file with all your provisioned services configured.</p>

<h3>16.5 Health Checks</h3>
<p>Each service has a built-in health check endpoint. The dashboard polls these to show live status badges (green = healthy, yellow = starting, red = down).</p>
</div>

<!-- ==================== 17. SECURITY ==================== -->
<div class="section" id="s17">
<h2>17. Security &amp; Compliance</h2>

<h3>17.1 Encryption</h3>
<p>Encrypt all stored data (sessions, memory, history):</p>
<pre><code># Generate a key (save this somewhere safe!)
python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"

# Set the key
export FAMILIAR_ENCRYPTION_KEY="your-generated-key"

# Enable in config.yaml
security:
  encrypt_sessions: true
  encrypt_memory: true
  encrypt_history: true</code></pre>

<h3>17.2 Compliance Modes</h3>
<table>
  <tr><th>Mode</th><th>Features</th><th>Who Needs It</th></tr>
  <tr><td><code>none</code></td><td>No enforcement (default)</td><td>Personal use</td></tr>
  <tr><td><code>hipaa</code></td><td>PHI detection, audit logging, encryption required</td><td>Healthcare organizations</td></tr>
  <tr><td><code>soc2</code></td><td>Access controls, audit trail</td><td>Businesses handling customer data</td></tr>
  <tr><td><code>gdpr</code></td><td>Data minimization, right to erasure</td><td>EU users / organizations</td></tr>
</table>

<div class="warn">
  <strong>Healthcare users:</strong> Install <code>pip install familiar-agent[healthcare]</code> and set <code>compliance.mode: hipaa</code> plus <code>agent.enable_pii_detection: true</code> in your config.
</div>
</div>

<!-- ==================== 18. MARKETPLACE ==================== -->
<div class="section" id="s18">
<h2>18. Marketplace &mdash; Custom Packages</h2>

<p>The Marketplace lets you install community-created <strong>job classes</strong>, <strong>skills</strong>, and <strong>bundles</strong> as JSON packages. Packages are stored in <code>~/.familiar/data/</code> and loaded automatically at startup.</p>

<h3>18.1 Package Types</h3>
<table>
  <tr><th>Type</th><th>What It Adds</th><th>Stored In</th></tr>
  <tr><td><strong>job_class</strong></td><td>A new job class with workspace panel, prompt fragment, and skill weights</td><td><code>~/.familiar/data/custom_job_classes/</code></td></tr>
  <tr><td><strong>skill</strong></td><td>Custom tools that extend Familiar's abilities</td><td><code>~/.familiar/data/custom_skills/</code></td></tr>
  <tr><td><strong>bundle</strong></td><td>A job class + one or more skills packaged together</td><td>Both directories above</td></tr>
</table>

<h3>18.2 Installing a Package</h3>
<p>Use the <code>/connect marketplace</code> wizard, or ask your Familiar in chat:</p>
<pre><code>"Install this job class package"
"Show me available marketplace packages"
"List my installed custom packages"</code></pre>

<p>Packages are JSON files. To install one from a file:</p>
<pre><code>python -c "
from familiar.jobs._marketplace import load_package_file, install_package
pkg = load_package_file('path/to/package.json')
print(install_package(pkg))
"</code></pre>

<h3>18.3 Package Format</h3>
<p>Every package is a JSON file with this structure:</p>
<pre><code>{
  "schema_version": "1.0",
  "type": "job_class",
  "metadata": {
    "id": "my_custom_role",
    "name": "My Custom Role",
    "version": "1.0.0",
    "author": "Your Name",
    "description": "What this role does.",
    "requires_skills": ["websearch", "tasks"],
    "familiar_version": ">=1.14.52"
  },
  "job_class": {
    "key": "my_custom_role",
    "name": "My Custom Role",
    "icon": "fa-star",
    "description": "...",
    "prompt_fragment": "You are a...",
    "skill_weights": {"websearch": 1.5},
    "workspace": { ... }
  }
}</code></pre>

<h3>18.4 Uninstalling a Package</h3>
<pre><code>"Uninstall the my_custom_role job class"
"Remove the calculator skill package"</code></pre>

<h3>18.5 Creating Your Own Package</h3>
<ol>
  <li>Start with an existing job class as a template (see <code>familiar/jobs/</code> for examples)</li>
  <li>Build your JSON file following the schema above</li>
  <li>The <code>workspace</code> dict drives the dashboard panel (tables, pipelines, summary cards)</li>
  <li>Validate with: <code>from familiar.jobs._marketplace import validate_package</code></li>
  <li>Share with others by distributing the JSON file</li>
</ol>

<div class="tip">
  <strong>Compatibility checking:</strong> Packages can declare a minimum Familiar version via <code>familiar_version</code> in metadata. Installation will warn if your version is too old.
</div>
</div>

<!-- ==================== 19. ANDROID & REFLECTION ==================== -->
<div class="section" id="s19">
<h2>19. Familiar on Android &amp; the Reflection Platform</h2>

<h3>19.1 Familiar for Android</h3>
<p>A native Android app (works great on GrapheneOS).</p>

<div class="step">
  <span class="step-num">1</span> Go to <strong>github.com/omegcrash/familiar-android/releases</strong><br>
  <span class="step-num">2</span> Download the latest <code>.apk</code> file<br>
  <span class="step-num">3</span> On your phone: Settings &rarr; Security &rarr; enable "Install from unknown sources"<br>
  <span class="step-num">4</span> Open the APK and install it<br>
  <span class="step-num">5</span> Grant notification permission when prompted<br>
  <span class="step-num">6</span> The app runs a local Python agent via Chaquopy &mdash; everything stays on your device
</div>

<table>
  <tr><th>Detail</th><th>Value</th></tr>
  <tr><td>Package</td><td><code>com.omegcrash.familiar</code></td></tr>
  <tr><td>Version</td><td>1.4.35 (versionCode 44)</td></tr>
  <tr><td>Min Android</td><td>8.0 (API 26)</td></tr>
  <tr><td>Distribution</td><td>GitHub Releases (no Google Play)</td></tr>
</table>

<h3>19.2 Reflection (Multi-Tenant Platform)</h3>
<p>If you need to host multiple agents for different users or teams:</p>
<pre><code>pip install reflection-agent
reflection</code></pre>
<table>
  <tr><th>Detail</th><th>Value</th></tr>
  <tr><td>PyPI Package</td><td><code>reflection-agent</code></td></tr>
  <tr><td>Version</td><td>2.0.41</td></tr>
  <tr><td>Depends on</td><td><code>familiar-agent>=1.15.5</code></td></tr>
</table>
</div>

<!-- ==================== 20. TROUBLESHOOTING ==================== -->
<div class="section" id="s20">
<h2>20. Troubleshooting &amp; FAQ</h2>

<h3>20.1 Installation Problems</h3>

<h4>"command not found: python3" or "python is not recognized"</h4>
<p>Python isn't installed or not in your PATH.</p>
<ul>
  <li><strong>Mac:</strong> <code>brew install python</code> or download from python.org</li>
  <li><strong>Ubuntu/Debian:</strong> <code>sudo apt update && sudo apt install python3 python3-pip python3-venv</code></li>
  <li><strong>Windows:</strong> Download from python.org. During install, check <strong>"Add Python to PATH"</strong></li>
</ul>

<h4>"No module named pip" or "pip: command not found"</h4>
<pre><code># Linux/Mac:
python3 -m ensurepip --upgrade

# Or reinstall pip:
curl https://bootstrap.pypa.io/get-pip.py | python3</code></pre>

<h4>"ERROR: externally-managed-environment" (PEP 668)</h4>
<p>Your OS protects system Python. Use a virtual environment (recommended):</p>
<pre><code>python3 -m venv ~/familiar-env
source ~/familiar-env/bin/activate
pip install familiar-agent[llm,web]</code></pre>

<h4>pip install hangs or is very slow</h4>
<ul>
  <li>Check your internet connection</li>
  <li>Try a different mirror: <code>pip install --index-url https://pypi.org/simple/ familiar-agent[llm,web]</code></li>
  <li>If behind a corporate proxy, set <code>HTTP_PROXY</code> and <code>HTTPS_PROXY</code> environment variables</li>
</ul>

<h4>"ERROR: Could not build wheels for..." (compilation errors)</h4>
<p>Some extras need C compilers. Install build tools:</p>
<pre><code># Ubuntu/Debian:
sudo apt install build-essential python3-dev libffi-dev

# Mac:
xcode-select --install

# Windows:
# Install Visual Studio Build Tools from visualstudio.microsoft.com</code></pre>

<h3>20.2 API Key &amp; Provider Problems</h3>

<h4>"No API key found" or "AuthenticationError"</h4>
<ul>
  <li>Verify the key is set: <code>echo $ANTHROPIC_API_KEY</code> (should print your key)</li>
  <li>Make sure you're setting the right variable for your provider</li>
  <li>On Windows, use <code>set</code> not <code>export</code>: <code>set ANTHROPIC_API_KEY=sk-ant-...</code></li>
  <li>Check for trailing spaces or quotes in the key</li>
  <li>Try setting it in <code>~/.familiar/.env</code>: <code>ANTHROPIC_API_KEY=sk-ant-...</code></li>
</ul>

<h4>"Ollama connection refused" or "Connection error to localhost:11434"</h4>
<ul>
  <li>Is Ollama running? Start it: <code>ollama serve</code></li>
  <li>Check if it's listening: <code>curl http://localhost:11434/api/tags</code></li>
  <li>If Ollama is on a different machine, update <code>llm.ollama_base_url</code> in config.yaml</li>
  <li>Make sure you've pulled a model: <code>ollama pull llama3.2</code></li>
</ul>

<h4>"Rate limit exceeded" or "429 Too Many Requests"</h4>
<ul>
  <li>You've hit your provider's rate limit. Wait a minute and try again</li>
  <li>Check your provider dashboard for usage limits</li>
  <li>Consider using a local model for high-volume tasks: <code>/model ollama</code></li>
</ul>

<h4>"Insufficient funds" or "billing error"</h4>
<ul>
  <li>Your API account needs credits. Add payment at your provider's billing page</li>
  <li>Anthropic: console.anthropic.com &rarr; Settings &rarr; Billing</li>
  <li>OpenAI: platform.openai.com &rarr; Settings &rarr; Billing</li>
</ul>

<h3>20.3 Dashboard Problems</h3>

<h4>Dashboard 401 Unauthorized</h4>
<ul>
  <li>If <code>FAMILIAR_DASHBOARD_KEY</code> is set, you need to provide it</li>
  <li>Check that the key in your browser matches exactly (no extra spaces)</li>
  <li>Try clearing browser storage: open DevTools (F12) &rarr; Application &rarr; Session Storage &rarr; Clear</li>
  <li>Or pass it via URL: <code>http://localhost:5000?api_key=your-key</code></li>
</ul>

<h4>Dashboard loads but shows a blank page or broken layout</h4>
<ul>
  <li><strong>Hard refresh:</strong> Press <code>Ctrl+Shift+R</code> (Windows/Linux) or <code>Cmd+Shift+R</code> (Mac)</li>
  <li><strong>Clear browser cache:</strong> Ctrl+Shift+Delete &rarr; select "Cached images and files" &rarr; Clear</li>
  <li><strong>Try incognito/private window</strong> to rule out extensions or cached data</li>
  <li><strong>Try a different browser</strong> (Chrome, Firefox, Edge all work)</li>
  <li>Check the terminal for error messages &mdash; they often explain what went wrong</li>
</ul>

<h4>Dashboard is slow, unresponsive, or spinner won't stop</h4>
<ul>
  <li>Refresh the page (<code>F5</code> or <code>Ctrl+R</code>)</li>
  <li>Check the terminal for errors (the agent might be waiting for an LLM response)</li>
  <li>If using a local model, it may be loading into memory &mdash; give it 30-60 seconds on first use</li>
  <li>Open browser DevTools (F12) &rarr; Console tab to see JavaScript errors</li>
</ul>

<h4>Creature sprite not showing</h4>
<ul>
  <li>Run <code>/start</code> in the chat to trigger creature creation</li>
  <li>Or run <code>python -m familiar --onboard</code> and complete the setup</li>
  <li>Check <code>~/.familiar/data/creature.json</code> exists</li>
  <li>Hard refresh the browser (<code>Ctrl+Shift+R</code>)</li>
</ul>

<h4>Changes don't appear after saving settings</h4>
<ul>
  <li>Hard refresh: <code>Ctrl+Shift+R</code></li>
  <li>The sidebar creature widget updates automatically, but other pages may need a refresh</li>
  <li>Check the terminal output for save errors</li>
</ul>

<h4>"Address already in use" / port 5000 conflict</h4>
<ul>
  <li>Another process is using port 5000. Find it: <code>lsof -i :5000</code> (Mac/Linux) or <code>netstat -ano | findstr 5000</code> (Windows)</li>
  <li>Use a different port: <code>python -m familiar --dashboard --dashboard-port 5001</code></li>
  <li>On Mac, AirPlay Receiver uses port 5000 &mdash; disable it in System Settings &rarr; AirDrop &amp; Handoff</li>
</ul>

<h3>20.4 Module &amp; Import Errors</h3>

<h4>"ModuleNotFoundError: No module named 'discord'" (or telegram, etc.)</h4>
<p>You need to install the relevant extra:</p>
<pre><code>pip install familiar-agent[discord]     # for Discord
pip install familiar-agent[telegram]    # for Telegram
pip install familiar-agent[voice]       # for voice features
pip install familiar-agent[web]         # for the dashboard</code></pre>

<h4>"ImportError" after upgrading</h4>
<pre><code># Force reinstall to clear stale files
pip install --force-reinstall familiar-agent[llm,web]</code></pre>

<h3>20.5 Creature &amp; Evolution Problems</h3>

<h4>Stage dropdown doesn't change the preview</h4>
<ul>
  <li>Hard refresh the page (<code>Ctrl+Shift+R</code>)</li>
  <li>Check browser console (F12) for JavaScript errors</li>
  <li>Verify the agent is running (check terminal for errors)</li>
</ul>

<h4>"Reset to Baby" doesn't work</h4>
<ul>
  <li>A confirmation dialog should appear &mdash; check for popup blockers</li>
  <li>Check the terminal for error messages</li>
  <li>Manual fix: edit <code>~/.familiar/data/creature.json</code> and set <code>"evolution_stage": "baby"</code> and <code>"total_interactions": 0</code></li>
</ul>

<h3>20.6 Connection &amp; Network Issues</h3>

<h4>Can't access dashboard from phone/another device</h4>
<ul>
  <li>By default, the dashboard only listens on localhost. Start with: <code>python -m familiar.dashboard --host 0.0.0.0</code></li>
  <li>Make sure both devices are on the same network</li>
  <li>Check firewall: <code>sudo ufw allow 5000</code> (Linux)</li>
  <li>Find your computer's IP: <code>hostname -I</code> (Linux) or <code>ipconfig</code> (Windows)</li>
</ul>

<h4>Mesh nodes can't connect</h4>
<ul>
  <li>Verify the gateway is running with <code>--public</code> flag</li>
  <li>Check firewall allows port 18789</li>
  <li>Verify the secret key matches on both sides</li>
  <li>Test connectivity: <code>curl http://gateway-ip:18789</code></li>
</ul>

<h3>20.7 Performance Issues</h3>

<h4>Agent responds very slowly</h4>
<ul>
  <li>Cloud providers: check your internet connection</li>
  <li>Local models: try a smaller model (<code>/connect ollama</code> &rarr; switch to a lighter model)</li>
  <li>Check RAM usage: local models need the full model loaded in memory</li>
  <li>On Raspberry Pi: use <code>tinyllama</code> or <code>smollm2:135m</code> for speed</li>
</ul>

<h4>High memory usage</h4>
<ul>
  <li>Local models require significant RAM. <code>llama3.2</code> needs ~4 GB</li>
  <li>Switch to a cloud provider to free memory: <code>/model claude</code></li>
  <li>Or use a smaller model: <code>/connect ollama</code> then switch to <code>phi3:mini</code></li>
</ul>

<h3>20.8 Logs &amp; Debugging</h3>
<pre><code># Enable verbose logging at startup:
python -m familiar --verbose --dashboard

# Or set log level in config.yaml:
observability:
  log_level: DEBUG</code></pre>
<p>Logs are printed to the terminal where Familiar is running. Look for lines marked <code>ERROR</code> or <code>WARNING</code>.</p>
</div>

<!-- ==================== 21. UNINSTALLING ==================== -->
<div class="section" id="s21">
<h2>21. Uninstalling, Reinstalling &amp; Clean Reset</h2>

<h3>21.1 Complete Uninstall</h3>
<p>Follow these steps to remove Familiar entirely from your system:</p>

<div class="step">
  <span class="step-num">1</span> <strong>Stop the agent</strong> if it's running (press <code>Ctrl+C</code> in the terminal or kill the process)<br>
</div>
<div class="step">
  <span class="step-num">2</span> <strong>Uninstall the Python package:</strong><br>
  <pre><code>pip uninstall familiar-agent -y</code></pre>
</div>
<div class="step">
  <span class="step-num">3</span> <strong>Remove all data and configuration:</strong><br>
  <pre><code># This deletes your config, creature, memories, and all data!
rm -rf ~/.familiar</code></pre>
  <p style="font-size:9pt; color:#666;">Windows: <code>rmdir /s /q %USERPROFILE%\.familiar</code></p>
</div>
<div class="step">
  <span class="step-num">4</span> <strong>Remove the virtual environment</strong> (if you created one):<br>
  <pre><code>rm -rf ~/familiar-env</code></pre>
</div>
<div class="step">
  <span class="step-num">5</span> <strong>Remove Ollama models</strong> (if installed):<br>
  <pre><code># List models:
ollama list

# Remove each one:
ollama rm llama3.2
ollama rm mistral
# etc.

# To uninstall Ollama itself:
# Mac: delete the app from Applications
# Linux: sudo rm /usr/local/bin/ollama && rm -rf ~/.ollama</code></pre>
</div>
<div class="step">
  <span class="step-num">6</span> <strong>Remove Reflection</strong> (if installed):<br>
  <pre><code>pip uninstall reflection-agent -y</code></pre>
</div>

<div class="danger">
  <strong>Warning:</strong> Step 3 permanently deletes all your data &mdash; creature state, memories, conversation history, configuration, and API keys stored in <code>~/.familiar/.env</code>. Back up anything important first!
</div>

<h3>21.2 Clean Reinstall</h3>
<p>To start completely fresh (like a brand-new setup):</p>

<pre><code># 1. Uninstall
pip uninstall familiar-agent -y

# 2. Remove all data
rm -rf ~/.familiar

# 3. Clear pip cache (fixes stale package issues)
pip cache purge

# 4. Reinstall
pip install familiar-agent[llm,web]

# 5. Run the onboarding wizard
python -m familiar --onboard</code></pre>

<h3>21.3 Upgrade Without Losing Data</h3>
<p>To update to the latest version while keeping your creature, memories, and config:</p>
<pre><code>pip install --upgrade familiar-agent[llm,web]</code></pre>
<p>Your data in <code>~/.familiar/</code> is preserved. The agent will pick up new features automatically.</p>

<h3>21.4 Reset Just the Creature (Keep Everything Else)</h3>
<pre><code># Option 1: Use the dashboard button
# Settings card → "Reset to Baby"

# Option 2: Delete creature file
rm ~/.familiar/data/creature.json
# Re-run onboard or /start to create a new creature</code></pre>

<h3>21.5 Reset Configuration Only</h3>
<pre><code># Delete config but keep data
rm ~/.familiar/config.yaml

# Re-run the wizard
python -m familiar --onboard</code></pre>

<h3>21.6 Downgrade to a Specific Version</h3>
<pre><code>pip install familiar-agent==1.14.39</code></pre>

<h3>21.7 Clearing Browser Data (Dashboard Issues)</h3>
<p>If the dashboard is behaving strangely after an update:</p>
<ol>
  <li><strong>Hard refresh:</strong> <code>Ctrl+Shift+R</code> (Windows/Linux) or <code>Cmd+Shift+R</code> (Mac)</li>
  <li><strong>Clear site data:</strong> Browser DevTools (F12) &rarr; Application tab &rarr; Storage &rarr; "Clear site data"</li>
  <li><strong>Clear just session storage:</strong> DevTools &rarr; Application &rarr; Session Storage &rarr; right-click &rarr; Clear</li>
  <li><strong>Try incognito/private mode</strong> to confirm the issue is cache-related</li>
</ol>
</div>

<!-- ==================== 22. QUICK REFERENCE ==================== -->
<div class="section" id="s22">
<h2>22. Quick Reference Card</h2>

<h3>Essential Commands</h3>
<pre><code># Start (always activate venv first!)
source ~/familiar-env/bin/activate
python -m familiar --dashboard

# First-time setup
python -m familiar --onboard

# Change settings
python -m familiar --reconfigure</code></pre>

<h3>Chat Commands Cheat Sheet</h3>
<pre><code>/help              Show commands       /status       System info
/model claude      Switch to Claude    /model ollama Switch to local
/remember key val  Save a fact         /recall query Search memories
/connect           Setup wizard        /connect status  Check services
/clear             Clear history       /start        Onboarding spread
/trust             Trust level         /budget       Spending status</code></pre>

<h3>Key File Locations</h3>
<pre><code>~/.familiar/config.yaml              # Configuration
~/.familiar/.env                     # API keys (auto-managed)
~/.familiar/data/creature.json       # Creature state
~/.familiar/data/analytics.db        # Analytics database
~/.familiar/data/tasks.json          # Task list
~/.familiar/data/mesh/messages.db    # Peer messages
~/.familiar/data/mesh/usage.db       # Mesh usage tracking
~/.familiar/services/state.json      # Server provisioning state</code></pre>

<h3>Current Versions (March 2026)</h3>
<table>
  <tr><th>Component</th><th>Version</th><th>Install</th></tr>
  <tr><td>Familiar</td><td>1.15.6</td><td><code>pip install familiar-agent</code></td></tr>
  <tr><td>Reflection</td><td>2.0.41</td><td><code>pip install reflection-agent</code></td></tr>
  <tr><td>Android</td><td>1.4.35</td><td>GitHub Releases APK</td></tr>
</table>

<h3>Getting Help</h3>
<ul>
  <li><strong>GitHub Issues:</strong> github.com/omegcrash/familiar/issues</li>
  <li><strong>Source Code:</strong> github.com/omegcrash/familiar</li>
</ul>
</div>
"""

# ── APPENDIX (command index) ─────────────────────────────────────────
APPENDIX = r"""
<!-- ==================== APPENDIX ==================== -->
<div class="section appendix" id="appendix">
<h1 style="font-size:22pt; text-align:center; border:none; margin-bottom:4px;">Appendix: Advanced Command &amp; Configuration Index</h1>
<p style="text-align:center; color:#666; margin-bottom:20px;">This section is a comprehensive reference for advanced users. It documents every CLI flag, chat command, API endpoint, configuration key, and environment variable in the Familiar platform.</p>

<!-- A1. CLI -->
<h2>A1. CLI Commands &amp; Flags</h2>

<h3><code>python -m familiar</code></h3>
<table>
<tr><th>Flag</th><th>Short</th><th>Default</th><th>Description</th></tr>
<tr><td><code>--telegram</code></td><td><code>-t</code></td><td></td><td>Run with Telegram</td></tr>
<tr><td><code>--discord</code></td><td></td><td></td><td>Run with Discord</td></tr>
<tr><td><code>--matrix</code></td><td></td><td></td><td>Run with Matrix</td></tr>
<tr><td><code>--github</code></td><td></td><td></td><td>GitHub notification polling</td></tr>
<tr><td><code>--slack</code></td><td></td><td></td><td>Slack (Socket Mode)</td></tr>
<tr><td><code>--dashboard</code></td><td><code>-d</code></td><td></td><td>Web dashboard</td></tr>
<tr><td><code>--dashboard-port</code></td><td></td><td>5000</td><td>Dashboard port</td></tr>
<tr><td><code>--gateway</code></td><td><code>-g</code></td><td></td><td>Mesh gateway mode</td></tr>
<tr><td><code>--gateway-port</code></td><td></td><td>18789</td><td>Gateway port</td></tr>
<tr><td><code>--provider</code></td><td><code>-p</code></td><td>ollama</td><td>LLM provider</td></tr>
<tr><td><code>--init</code></td><td></td><td></td><td>Initialize config</td></tr>
<tr><td><code>--onboard</code></td><td></td><td></td><td>Onboarding wizard</td></tr>
<tr><td><code>--onboard-tui</code></td><td></td><td></td><td>Rich TUI onboarding</td></tr>
<tr><td><code>--reconfigure</code></td><td></td><td></td><td>Re-run onboarding</td></tr>
<tr><td><code>--setup-google</code></td><td></td><td></td><td>Google Workspace</td></tr>
<tr><td><code>--new-skill NAME</code></td><td></td><td></td><td>Create skill template</td></tr>
<tr><td><code>--show-key</code></td><td></td><td></td><td>Show mesh key</td></tr>
<tr><td><code>--verbose</code></td><td><code>-v</code></td><td></td><td>Verbose logging</td></tr>
</table>

<h3>Other Entry Points</h3>
<table>
<tr><th>Command</th><th>Port</th><th>Description</th></tr>
<tr><td><code>python -m familiar.dashboard</code></td><td>5000</td><td>Dashboard (--host, --port, --debug)</td></tr>
<tr><td><code>python -m familiar.admin</code></td><td>5001</td><td>Admin dashboard</td></tr>
<tr><td><code>python -m familiar.pwa</code></td><td>5002</td><td>PWA server</td></tr>
<tr><td><code>familiar-mesh gateway|node|status|genkey</code></td><td>18789</td><td>Mesh CLI</td></tr>
<tr><td><code>familiar-eval run|generate</code></td><td></td><td>CI evaluation</td></tr>
<tr><td><code>python -m familiar.core.mcp.server</code></td><td></td><td>MCP skill server</td></tr>
<tr><td><code>python -m familiar.core.backup</code></td><td></td><td>Backup tool</td></tr>
<tr><td><code>python -m familiar.channels.teams</code></td><td>3978</td><td>Teams bot</td></tr>
</table>

<!-- A2. CHAT COMMANDS -->
<h2>A2. All Chat Commands</h2>
<table>
<tr><th>Command</th><th>Scope</th><th>Description</th></tr>
<tr><td><code>/help</code></td><td>All</td><td>Show commands</td></tr>
<tr><td><code>/start</code></td><td>All</td><td>Tarot onboarding</td></tr>
<tr><td><code>/status</code></td><td>All</td><td>System status</td></tr>
<tr><td><code>/clear</code></td><td>All</td><td>Clear history</td></tr>
<tr><td><code>/model [name]</code></td><td>All</td><td>Show/switch provider</td></tr>
<tr><td><code>/remember &lt;key&gt; &lt;value&gt;</code></td><td>All</td><td>Store memory</td></tr>
<tr><td><code>/recall &lt;query&gt;</code></td><td>All</td><td>Search memories</td></tr>
<tr><td><code>/trust</code></td><td>All</td><td>Trust level</td></tr>
<tr><td><code>/budget</code></td><td>All</td><td>Spending status</td></tr>
<tr><td><code>/caps</code></td><td>All</td><td>Capabilities</td></tr>
<tr><td><code>/connect [service]</code></td><td>All</td><td>Connection wizard</td></tr>
<tr><td><code>/browse</code></td><td>All</td><td>Browse services</td></tr>
<tr><td><code>/search &lt;svc&gt; &lt;q&gt;</code></td><td>All</td><td>Search service</td></tr>
<tr><td><code>/quit</code></td><td>CLI</td><td>Exit</td></tr>
<tr><td><code>/models</code></td><td>CLI</td><td>List providers</td></tr>
<tr><td><code>/skills</code></td><td>CLI</td><td>List skills</td></tr>
<tr><td><code>/tools</code></td><td>CLI</td><td>List tools</td></tr>
<tr><td><code>/creature</code></td><td>CLI</td><td>Creature stats</td></tr>
<tr><td><code>/link &lt;email&gt;</code></td><td>Multi-user</td><td>Link account</td></tr>
<tr><td><code>/confirm &lt;code&gt;</code></td><td>Multi-user</td><td>Confirm link</td></tr>
<tr><td><code>/unlink</code></td><td>Multi-user</td><td>Unlink account</td></tr>
<tr><td><code>/whoami</code></td><td>Multi-user</td><td>Account info</td></tr>
<tr><td><code>/grant &lt;id&gt; [role]</code></td><td>Owner</td><td>Grant access</td></tr>
<tr><td><code>/revoke &lt;id&gt;</code></td><td>Owner</td><td>Revoke access</td></tr>
<tr><td><code>/preauth</code></td><td>Owner</td><td>List pre-auth users</td></tr>
<tr><td><code>/ask &lt;question&gt;</code></td><td>Discord</td><td>Ask the agent</td></tr>
</table>

<!-- A3. CONNECT WIZARD -->
<h2>A3. Connect Wizard Commands (70+)</h2>
<h4>LLM: <code>/connect anthropic|openai|gemini|ollama</code></h4>
<h4>Email: <code>/connect email [gmail|outlook|yahoo|proton|custom] | email test | email set</code></h4>
<h4>Calendar: <code>/connect calendar [google|caldav] | calendar test</code></h4>
<h4>Google: <code>/connect google [check|install|auth &lt;svc&gt;|code &lt;code&gt;]</code></h4>
<h4>Integrations: <code>/connect sms|browser|voice|healthcare|websearch|github|slack</code></h4>
<h4>Self-hosted: <code>/connect jellyfin|gitea|homeassistant|joplin|pihole|nextcloud|proton|email-server</code></h4>
<h4>Security: <code>/connect security|vaultwarden|encryption|phi|rbac|users</code></h4>
<p>Each service supports <code>test</code> subcommand and inline one-shot setup with arguments.</p>

<!-- A4. API ENDPOINTS -->
<h2>A4. Dashboard API Endpoints (79 routes)</h2>
<table>
<tr><th>#</th><th>Method</th><th>Path</th><th>Description</th></tr>
<tr><td>1</td><td>GET</td><td><code>/</code></td><td>Dashboard page</td></tr>
<tr><td>2</td><td>GET</td><td><code>/api/status</code></td><td>System status</td></tr>
<tr><td>3</td><td>GET</td><td><code>/api/creature</code></td><td>Creature state</td></tr>
<tr><td>4</td><td>POST</td><td><code>/api/creature</code></td><td>Update creature</td></tr>
<tr><td>5</td><td>GET</td><td><code>/api/creature/preview</code></td><td>Sprite preview</td></tr>
<tr><td>6</td><td>POST</td><td><code>/api/chat</code></td><td>Send message</td></tr>
<tr><td>7</td><td>POST</td><td><code>/api/terminal/stream</code></td><td>Stream response (SSE)</td></tr>
<tr><td>8</td><td>POST</td><td><code>/api/voice/stt</code></td><td>Speech-to-text</td></tr>
<tr><td>9</td><td>POST</td><td><code>/api/voice/tts</code></td><td>Text-to-speech</td></tr>
<tr><td>10-13</td><td>*</td><td><code>/api/shell/*</code></td><td>Host shell (enable, stream, kill)</td></tr>
<tr><td>14-16</td><td>*</td><td><code>/api/memory[/&lt;key&gt;]</code></td><td>Memory CRUD</td></tr>
<tr><td>17-19</td><td>*</td><td><code>/api/tasks[/&lt;id&gt;/complete]</code></td><td>Task management</td></tr>
<tr><td>20-22</td><td>*</td><td><code>/api/skills[/&lt;name&gt;/toggle]</code>, <code>/api/tools</code></td><td>Skills &amp; tools</td></tr>
<tr><td>23</td><td>GET</td><td><code>/api/nodes</code></td><td>Mesh nodes</td></tr>
<tr><td>24-26</td><td>GET</td><td><code>/api/email/*</code>, <code>/api/briefing</code></td><td>Email triage, briefing</td></tr>
<tr><td>27-38</td><td>*</td><td><code>/api/connect/*</code></td><td>Connect wizard, browse, search</td></tr>
<tr><td>39-42</td><td>*</td><td><code>/api/config[/routing]</code></td><td>Config &amp; model routing</td></tr>
<tr><td>43-44</td><td>*</td><td><code>/api/history</code></td><td>Conversation history</td></tr>
<tr><td>45-55</td><td>*</td><td><code>/onboard</code>, <code>/api/onboard/*</code></td><td>Onboarding (11 routes)</td></tr>
<tr><td>56</td><td>GET</td><td><code>/api/workspace</code></td><td>Workspace config + overview metrics</td></tr>
<tr><td>57</td><td>GET</td><td><code>/api/workspace/section/&lt;key&gt;</code></td><td>Section data (sort, page, limit)</td></tr>
<tr><td>58</td><td>POST</td><td><code>/api/workspace/action</code></td><td>Execute workspace action (tool or agent)</td></tr>
<tr><td>59-65</td><td>*</td><td><code>/api/messages/*</code></td><td>Peer messaging (list, send, read, typing, poll, conversations, history)</td></tr>
<tr><td>66-71</td><td>*</td><td><code>/api/social/*</code></td><td>Social dashboard (accounts, config, feed, notifications, post, poll)</td></tr>
<tr><td>72-79</td><td>*</td><td><code>/api/server/*</code></td><td>Server provisioning (runtime, status, provision, start, stop, restart, remove, logs)</td></tr>
</table>

<h3>Admin Endpoints (29 routes, port 5001)</h3>
<p>Login, users, invites, activity, settings, analytics, budgets, audit, backups, SSO.</p>

<h3>PWA Endpoints (13 routes, port 5002)</h3>
<p>Chat, streaming, push notifications, user info.</p>

<h3>Other (19 routes)</h3>
<p>HA health/status/drain (4), audit (4), SSO (3), browser proxy (12).</p>

<!-- A5. CONFIG KEYS -->
<h2>A5. YAML Configuration Keys (97 keys)</h2>

<h3><code>agent.*</code></h3>
<table>
<tr><th>Key</th><th>Type</th><th>Default</th></tr>
<tr><td><code>name</code></td><td>str</td><td>"Agent"</td></tr>
<tr><td><code>persona</code></td><td>str</td><td>"a helpful AI assistant"</td></tr>
<tr><td><code>memory_enabled</code></td><td>bool</td><td>true</td></tr>
<tr><td><code>max_conversation_history</code></td><td>int</td><td>50</td></tr>
<tr><td><code>skills_enabled</code></td><td>bool</td><td>true</td></tr>
<tr><td><code>scheduler_enabled</code></td><td>bool</td><td>true</td></tr>
<tr><td><code>heartbeat_interval_minutes</code></td><td>int</td><td>60</td></tr>
<tr><td><code>security_mode</code></td><td>str</td><td>"balanced"</td></tr>
<tr><td><code>allow_shell_commands</code></td><td>bool</td><td>true</td></tr>
<tr><td><code>allow_file_write</code></td><td>bool</td><td>true</td></tr>
<tr><td><code>enable_pii_detection</code></td><td>bool</td><td>false</td></tr>
<tr><td><code>sandboxed_directories</code></td><td>list</td><td>[HOME]</td></tr>
</table>

<h3><code>llm.*</code></h3>
<table>
<tr><th>Key</th><th>Type</th><th>Default</th></tr>
<tr><td><code>default_provider</code></td><td>str</td><td>"anthropic"</td></tr>
<tr><td><code>anthropic_model</code></td><td>str</td><td>"claude-sonnet-4-6"</td></tr>
<tr><td><code>openai_model</code></td><td>str</td><td>"gpt-4o"</td></tr>
<tr><td><code>ollama_model</code></td><td>str</td><td>"llama3.2"</td></tr>
<tr><td><code>ollama_base_url</code></td><td>str</td><td>"http://localhost:11434"</td></tr>
<tr><td><code>max_tokens</code></td><td>int</td><td>4096</td></tr>
<tr><td><code>temperature</code></td><td>float</td><td>0.7</td></tr>
<tr><td><code>lightweight_model</code></td><td>str</td><td>""</td></tr>
<tr><td><code>lightweight_provider</code></td><td>str</td><td>""</td></tr>
</table>

<h3><code>channels.*</code> (17 keys)</h3>
<p><code>cli_enabled</code>(true), <code>telegram_enabled</code>(false), <code>telegram_token</code>, <code>telegram_allowed_users</code>, <code>owner_telegram_id</code>, <code>discord_enabled</code>(false), <code>discord_token</code>, <code>matrix_enabled</code>(false), <code>matrix_homeserver</code>, <code>matrix_user</code>, <code>signal_enabled</code>(false), <code>whatsapp_enabled</code>(false), <code>imessage_enabled</code>(false), <code>teams_enabled</code>(false), and associated tokens/IDs.</p>

<h3><code>security.*</code> (11 keys)</h3>
<p><code>encrypt_sessions</code>(false), <code>encrypt_memory</code>(false), <code>encrypt_history</code>(false), <code>encryption_key_env</code>, <code>session_timeout_minutes</code>(60), <code>require_reauth_for_sensitive</code>(false), <code>max_failed_attempts</code>(5), <code>lockout_duration_minutes</code>(30), <code>auto_trust_upgrade</code>(true), <code>max_trust_level</code>("owner"), <code>always_confirm</code>(list).</p>

<h3><code>compliance.*</code> (4), <code>proactive.*</code> (5), <code>resilience.*</code> (6), <code>observability.*</code> (5), <code>mcp.*</code> (11), <code>backup.*</code> (11)</h3>
<p>See Sections 4 and 17 of the main guide for full details.</p>

<!-- A6. ENV VARS -->
<h2>A6. Environment Variables (160+)</h2>

<h3>API Keys</h3>
<p><code>ANTHROPIC_API_KEY</code>, <code>OPENAI_API_KEY</code>, <code>GEMINI_API_KEY</code>, <code>GOOGLE_API_KEY</code></p>

<h3>LLM Overrides</h3>
<p><code>DEFAULT_PROVIDER</code>, <code>LLM_DEFAULT_PROVIDER</code>, <code>OLLAMA_MODEL</code>, <code>OLLAMA_TIMEOUT</code>, <code>OLLAMA_NUM_CTX</code>, <code>OLLAMA_FALLBACK_MODEL</code>, <code>GEMINI_MODEL</code>, <code>FAMILIAR_LIGHTWEIGHT_MODEL</code>, <code>FAMILIAR_LIGHTWEIGHT_PROVIDER</code>, <code>AGENT_NAME</code></p>

<h3>Channel Tokens</h3>
<p><code>TELEGRAM_BOT_TOKEN</code>, <code>DISCORD_BOT_TOKEN</code>, <code>GITHUB_TOKEN</code>, <code>GITHUB_REPOS</code>, <code>SLACK_BOT_TOKEN</code>, <code>SLACK_APP_TOKEN</code>, <code>MATRIX_HOMESERVER</code>, <code>MATRIX_USER</code>, <code>MATRIX_PASSWORD</code>, <code>MATRIX_ACCESS_TOKEN</code>, <code>SIGNAL_PHONE</code>, <code>WHATSAPP_BRIDGE_HOST</code>, <code>TEAMS_APP_ID</code>, <code>TEAMS_APP_PASSWORD</code>, <code>ENABLED_CHANNELS</code></p>

<h3>Owner Identity</h3>
<p><code>OWNER_TELEGRAM_ID</code>, <code>OWNER_DISCORD_ID</code>, <code>OWNER_MATRIX_ID</code>, <code>OWNER_SIGNAL_ID</code>, <code>OWNER_WHATSAPP_ID</code>, <code>OWNER_IMESSAGE_ID</code>, <code>OWNER_TEAMS_ID</code>, <code>OWNER_GITHUB_ID</code>, <code>OWNER_SLACK_ID</code>, <code>OWNER_PIN_HASH</code></p>

<h3>Email</h3>
<p><code>EMAIL_ADDRESS</code>, <code>EMAIL_PASSWORD</code>, <code>EMAIL_IMAP_SERVER</code>, <code>EMAIL_SMTP_SERVER</code>, <code>EMAIL_IMAP_PORT</code>, <code>EMAIL_SMTP_PORT</code>, <code>EMAIL_SERVER_DOMAIN</code>, <code>EMAIL_SERVER_RELAY_HOST</code>, <code>FAMILIAR_EMAIL_ADDRESS</code>, <code>FAMILIAR_SMTP_SERVER</code></p>

<h3>Self-Hosted Services</h3>
<p><code>JELLYFIN_URL/TOKEN/USER_ID</code>, <code>GITEA_URL/TOKEN</code>, <code>HOMEASSISTANT_URL/TOKEN</code>, <code>JOPLIN_URL/TOKEN</code>, <code>PIHOLE_URL/TOKEN/TYPE</code>, <code>NEXTCLOUD_URL/USER/TOKEN</code>, <code>VAULTWARDEN_URL/TOKEN</code>, <code>CALDAV_URL/USER/PASSWORD</code>, <code>PROTON_BRIDGE_HOST</code>, <code>TWILIO_ACCOUNT_SID/AUTH_TOKEN/PHONE_NUMBER</code>, <code>MEALIE_URL/TOKEN</code>, <code>JITSI_URL</code></p>

<h3>Social Media</h3>
<p><code>BLUESKY_HANDLE</code>, <code>BLUESKY_APP_PASSWORD</code>, <code>BLUESKY_PDS_URL</code>, <code>MASTODON_INSTANCE_URL</code>, <code>MASTODON_ACCESS_TOKEN</code></p>

<h3>CRM &amp; Marketing</h3>
<p><code>HUBSPOT_ACCESS_TOKEN</code>, <code>CIVICRM_URL/API_KEY/SITE_KEY</code>, <code>MAILERLITE_API_KEY</code></p>

<h3>Payments &amp; Finance</h3>
<p><code>STRIPE_SECRET_KEY</code>, <code>SQUARE_ACCESS_TOKEN</code>, <code>QUICKBOOKS_ACCESS_TOKEN/REALM_ID</code></p>

<h3>Tasks &amp; Time Tracking</h3>
<p><code>TODOIST_API_TOKEN</code>, <code>CLOCKIFY_API_KEY/WORKSPACE_ID</code>, <code>CALCOM_API_KEY</code></p>

<h3>E-Commerce &amp; Shipping</h3>
<p><code>ETSY_API_KEY/SHOP_ID</code>, <code>SHIPPO_API_KEY</code>, <code>CLOUDINARY_CLOUD_NAME/API_KEY</code></p>

<h3>Social &amp; Content</h3>
<p><code>REDDIT_CLIENT_ID/CLIENT_SECRET</code>, <code>INSTAGRAM_ACCESS_TOKEN/BUSINESS_ID</code>, <code>GOOGLE_TRENDS_API_KEY</code></p>

<h3>Search &amp; News</h3>
<p><code>BRAVE_SEARCH_API_KEY</code>, <code>GNEWS_API_KEY</code>, <code>NEWSDATA_API_KEY</code></p>

<h3>Healthcare &amp; Social Services</h3>
<p><code>OPEN_REFERRAL_URL</code>, <code>KOBO_URL/TOKEN</code></p>

<h3>Grants &amp; Research</h3>
<p><code>GRANTS_GOV_API_KEY</code>, <code>GLOBALGIVING_API_KEY</code></p>

<h3>Food &amp; Recipes</h3>
<p><code>SPOONACULAR_API_KEY</code>, <code>FOODDATA_API_KEY</code></p>

<h3>Dashboard &amp; Web</h3>
<p><code>FAMILIAR_DASHBOARD_KEY</code>, <code>FAMILIAR_ALLOWED_ORIGINS</code>, <code>FAMILIAR_SHELL_ENABLED</code>, <code>FAMILIAR_ONBOARD_LAN</code>, <code>FAMILIAR_ADMIN_SECRET</code>, <code>FAMILIAR_PWA_SECRET</code>, <code>FAMILIAR_DATA_DIR</code>, <code>VAPID_PUBLIC_KEY</code>, <code>VAPID_PRIVATE_KEY</code></p>

<h3>Security &amp; Encryption</h3>
<p><code>FAMILIAR_ENCRYPTION_KEY</code>, <code>FAMILIAR_ENCRYPTION_PASSWORD</code>, <code>FAMILIAR_AUDIT_KEY</code>, <code>FAMILIAR_WEBHOOK_SECRET</code></p>

<h3>Mesh &amp; HA</h3>
<p><code>FAMILIAR_MESH_ENABLED</code>, <code>FAMILIAR_MESH_HOST</code>, <code>FAMILIAR_MESH_PORT</code>, <code>FAMILIAR_MESH_KEY</code>, <code>FAMILIAR_NODE_NAME</code>, <code>HA_ENABLED</code>, <code>HA_MODE</code>, <code>HA_NODE_ID</code>, <code>HA_SHARED_SECRET</code></p>

<h3>Redis</h3>
<p><code>REDIS_URL</code>, <code>REDIS_HOST</code>, <code>REDIS_PORT</code>, <code>REDIS_DB</code>, <code>REDIS_PASSWORD</code>, <code>FAMILIAR_REDIS_PREFIX</code></p>

<h3>SSO</h3>
<p><code>SSO_PROVIDER</code>, <code>SSO_CLIENT_ID</code>, <code>SSO_REDIRECT_URI</code>, <code>SSO_ALLOWED_DOMAINS</code>, <code>GOOGLE_CLIENT_ID</code>, <code>GOOGLE_CLIENT_SECRET</code>, <code>MICROSOFT_CLIENT_ID</code>, <code>MICROSOFT_CLIENT_SECRET</code></p>

<h3>Embeddings</h3>
<p><code>FAMILIAR_EMBEDDING_URL</code>, <code>FAMILIAR_EMBEDDING_DIM</code>, <code>FAMILIAR_EMBEDDING_KEY</code>, <code>FAMILIAR_EMBEDDING_MODEL</code>, <code>VOYAGE_API_KEY</code></p>

<h3>CI/Eval</h3>
<p><code>FAMILIAR_MIN_PASS_RATE</code>, <code>FAMILIAR_MAX_CRITICAL_FAILURES</code>, <code>FAMILIAR_MAX_HIGH_FAILURES</code>, <code>FAMILIAR_MAX_LATENCY_MS</code>, <code>FAMILIAR_MAX_COST_USD</code>, <code>FAMILIAR_FAIL_ON_CRITICAL</code>, <code>FAMILIAR_BAA_CONFIRMED</code></p>

<!-- A7. DATA PATHS -->
<h2>A7. Data Paths</h2>
<table>
<tr><th>Path</th><th>Purpose</th></tr>
<tr><td><code>~/.familiar/config.yaml</code></td><td>Configuration</td></tr>
<tr><td><code>~/.familiar/.env</code></td><td>Environment variables</td></tr>
<tr><td><code>~/.familiar/data/creature.json</code></td><td>Creature state</td></tr>
<tr><td><code>~/.familiar/data/analytics.db</code></td><td>Analytics database</td></tr>
<tr><td><code>~/.familiar/data/tasks.json</code></td><td>Task list</td></tr>
<tr><td><code>~/.familiar/data/nonprofit.json</code></td><td>Donor, grant, and nonprofit data</td></tr>
<tr><td><code>~/.familiar/data/bookkeeping.json</code></td><td>Financial transactions</td></tr>
<tr><td><code>~/.familiar/data/contacts.json</code></td><td>Unified address book</td></tr>
<tr><td><code>~/.familiar/data/training/curated/</code></td><td>Training data</td></tr>
<tr><td><code>~/.familiar/data/custom_job_classes/</code></td><td>Marketplace job class packages</td></tr>
<tr><td><code>~/.familiar/data/custom_skills/</code></td><td>Marketplace skill packages</td></tr>
<tr><td><code>~/.familiar/data/google_credentials.json</code></td><td>Google OAuth</td></tr>
<tr><td><code>~/.familiar/data/familiar_guide.pdf</code></td><td>Cached user guide PDF</td></tr>
<tr><td><code>~/.familiar/data/mesh/messages.db</code></td><td>Peer messaging database</td></tr>
<tr><td><code>~/.familiar/data/mesh/usage.db</code></td><td>Mesh usage tracking database</td></tr>
<tr><td><code>~/.familiar/services/state.json</code></td><td>Server provisioning state</td></tr>
<tr><td><code>~/.familiar/services/&lt;key&gt;/</code></td><td>Container data volumes</td></tr>
<tr><td><code>~/.familiar/backups/</code></td><td>Backup archives</td></tr>
<tr><td><code>~/.familiar/skills/</code></td><td>Custom user skills</td></tr>
<tr><td><code>~/.familiar/templates/</code></td><td>User document templates</td></tr>
</table>

<div style="margin-top:20px; padding:12px; background:#f0f0f5; border-radius:6px; text-align:center; font-size:9pt; color:#666;">
<strong>Totals:</strong> 17 CLI flags &bull; 26 chat commands &bull; 70+ connect wizard commands &bull; 144 API endpoints &bull; 97 config keys &bull; 160+ environment variables &bull; 80+ skills &bull; 6 job classes &bull; 8 self-hosted services
</div>

</div>
"""

# ── Public API ────────────────────────────────────────────────────────


def _get_version() -> str:
    """Return the installed familiar-agent version string."""
    try:
        from importlib.metadata import version

        return version("familiar-agent")
    except Exception:
        return "dev"


def get_guide_html() -> str:
    """Return the full user guide as an HTML string."""
    return (
        "<!DOCTYPE html>\n"
        '<html lang="en">\n'
        f"<head><meta charset=\"UTF-8\"><style>{STYLES}</style></head>\n"
        f"<body>\n{MAIN_GUIDE}\n{APPENDIX}\n</body>\n</html>"
    )


def generate_guide_pdf(output_path: str | Path | None = None) -> Path:
    """Render the guide to PDF, caching by version.

    Args:
        output_path: Explicit output file. When ``None`` the PDF is
            cached at ``~/.familiar/data/familiar_guide.pdf`` and only
            regenerated when the package version changes.

    Returns:
        Path to the generated PDF file.

    Raises:
        ImportError: If WeasyPrint is not installed.
    """
    try:
        from familiar.core.paths import DATA_DIR
    except ImportError:
        DATA_DIR = Path.home() / ".familiar" / "data"

    if output_path is not None:
        dest = Path(output_path)
    else:
        DATA_DIR.mkdir(parents=True, exist_ok=True)
        dest = DATA_DIR / "familiar_guide.pdf"
        stamp_file = DATA_DIR / ".guide_version"
        current_ver = _get_version()
        if dest.exists() and stamp_file.exists():
            try:
                if stamp_file.read_text().strip() == current_ver:
                    return dest
            except OSError as e:
                logger.debug("I/O error suppressed: %s", e)
    import weasyprint  # noqa: F811 — optional dependency

    html_str = get_guide_html()
    weasyprint.HTML(string=html_str).write_pdf(str(dest))
    logger.info("Generated guide PDF at %s", dest)

    # Write version stamp for cache invalidation
    if output_path is None:
        try:
            stamp_file.write_text(_get_version())
        except OSError as e:
            logger.debug("I/O error suppressed: %s", e)
    return dest
