https://github.com/famclaw/famclaw
Self-hosted family AI gateway with parental controls. Runs on Linux, macOS, and Android (Termux) β Raspberry Pi, mini PC, old laptop, homelab server, even a phone. Telegram, Discord, web. Privacy-first, works with any LLM (local or cloud), OPA content filtering, MCP skill scanning.
https://github.com/famclaw/famclaw
ai-assistant chatbot chatgpt-alternative discord-bot family go homelab llm local-first local-llm mcp ollama openclaw parental-control picoclaw privacy raspberry-pi self-hosted self-hosted-ai telegram-bot
Last synced: about 2 months ago
JSON representation
Self-hosted family AI gateway with parental controls. Runs on Linux, macOS, and Android (Termux) β Raspberry Pi, mini PC, old laptop, homelab server, even a phone. Telegram, Discord, web. Privacy-first, works with any LLM (local or cloud), OPA content filtering, MCP skill scanning.
- Host: GitHub
- URL: https://github.com/famclaw/famclaw
- Owner: famclaw
- License: agpl-3.0
- Created: 2026-03-19T02:59:01.000Z (4 months ago)
- Default Branch: main
- Last Pushed: 2026-05-06T22:55:15.000Z (about 2 months ago)
- Last Synced: 2026-05-06T23:33:44.267Z (about 2 months ago)
- Topics: ai-assistant, chatbot, chatgpt-alternative, discord-bot, family, go, homelab, llm, local-first, local-llm, mcp, ollama, openclaw, parental-control, picoclaw, privacy, raspberry-pi, self-hosted, self-hosted-ai, telegram-bot
- Language: Go
- Homepage:
- Size: 607 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
- Codeowners: CODEOWNERS
- Security: SECURITY.md
- Agents: AGENTS.md
Awesome Lists containing this project
README
# π‘οΈ FamClaw
**A secure, local-first family AI gateway. Runs on Raspberry Pi, Mac, or any Linux box.**
FamClaw is a lightweight Go gateway that connects your family to any AI model β local or cloud β through Telegram, WhatsApp, Discord, and a web interface. Every message goes through a policy engine before the AI ever sees it.
---
## What it is
- **A gateway, not an AI.** FamClaw routes messages between your family and whatever LLM you configure β Ollama on your home server, OpenAI, Anthropic, OpenRouter, or any OpenAI-compatible endpoint.
- **A policy enforcer.** Every message is evaluated by OPA (Open Policy Agent) before reaching the LLM. Kids get age-appropriate responses. Sensitive topics require parental approval.
- **A family assistant.** Age-aware profiles, parental approval workflow, notification to parents via email/SMS/Slack/Discord/ntfy.
---
## How it works
```
Family member sends message
β via Telegram / WhatsApp / Discord / Web UI
β FamClaw identifies user from gateway account
β OPA policy evaluates: allow / block / request approval
β if allow: forwards to your LLM endpoint
β streams response back
```
FamClaw itself uses ~20MB RAM. The LLM runs elsewhere β on a Mac Mini on your LAN, a cloud API, or any OpenAI-compatible server.
---
## Hardware
| Device | Role |
|--------|------|
| Raspberry Pi 3/4/5 | Run FamClaw 24/7, flash SD card and plug in |
| Mac Mini | Run as background daemon |
| Any Linux box | One binary, no dependencies |
---
## LLM backends
FamClaw talks to any OpenAI-compatible endpoint:
| Platform | Backend | api_key needed |
|---|---|---|
| RPi 3/4/5 | Ollama (local, auto-installed by firstboot.sh) | No |
| Mac Mini | Ollama (local) | No |
| Old Android (Termux) | OpenAI / Anthropic / OpenRouter / another device's Ollama | Yes (or LAN URL) |
| Any device | Can point at RPi's Ollama on LAN | No |
| Any device | Claude CLI (`provider: claude_cli`) | No (uses local claude binary) |
```yaml
llm:
primary:
base_url: "http://192.168.1.10:11434" # Ollama on your Mac Mini
model: "llama3.2:3b"
fallbacks:
- base_url: "https://api.openai.com/v1"
model: "gpt-4o-mini"
api_key: "${OPENAI_API_KEY}"
```
---
## Quick start
### Raspberry Pi (flash and plug in)
```bash
# Flash famclaw-rpi4-arm64.img.xz to SD card with Raspberry Pi Imager
# Plug in, wait 2 minutes, find the device IP from your router and open:
http://:8080
```
> mDNS (`famclaw.local`) was removed in v0.5.x because it didn't resolve
> reliably on Windows or many home routers. Use the device's IP address
> from your router's DHCP leases page or `ip addr` on the Pi.
### Mac / Linux
```bash
curl -fsSL https://github.com/famclaw/famclaw/releases/latest/download/install.sh | bash
```
### Build from source
```bash
git clone https://github.com/famclaw/famclaw
cd famclaw
make build
./bin/famclaw --config config.yaml
```
---
## Messaging gateways
| Gateway | Status |
|---------|--------|
| Web UI | Built β HTTP + WebSocket + embedded UI |
| Telegram | Built β long-poll Bot API |
| Discord | Built β via discordgo |
| WhatsApp | Placeholder β needs whatsmeow QR pairing |
Each family member's gateway account maps to their profile. Emma's Telegram account β Emma's age policy. Parent's Discord account β parent access.
---
## Policy system
Policies are [OPA Rego](https://www.openpolicyagent.org/) files. The default rule set lives at `internal/policy/policies/` and is **embedded in the binary** via `go:embed` β a downloaded release runs without any external policy directory. To override with custom rules, set `policies.dir` (and `policies.data_dir`) in `config.yaml` to a directory of your own `.rego` and JSON files. Run `opa test internal/policy/policies/family/ internal/policy/policies/data/ -v` to test the built-in rules locally.
Three tiers per age group:
```
allow β goes straight to LLM
request_approval β parent gets notified, child waits
block β never reaches LLM
```
Default age groups: `under_8`, `age_8_12`, `age_13_17`, `parent`.
---
## Skills
FamClaw uses the [AgentSkills](https://docs.openclaw.ai/tools/skills) spec β the same `SKILL.md` format used by OpenClaw, PicoClaw, and NanoBot. Skills from [famclaw/skills](https://github.com/famclaw/skills) work in all four runtimes. [HoneyBadger](https://github.com/famclaw/honeybadger) scans every skill before installation.
```bash
famclaw skill install seccheck
```
---
## Agent dispatch (`spawn_agent`)
The parent LLM can delegate sub-tasks to a different LLM profile via a built-in tool. Use it to send research-style or compute-heavy work to a local model (e.g., Qwen3-14B on Ollama) while the parent stays on a fast/cloud model.
```jsonc
// Tool call from the parent LLM:
{
"name": "builtin__spawn_agent",
"arguments": {
"prompt": "Summarize the key risks in the attached log",
"profile": "qwen3-local", // optional: omit to use the default profile
"timeout_seconds": 120, // default 300, capped at 1800
"tools": ["fs.read", "web.search"], // allowlist; omit for NO MCP tools (default-deny)
"deny_tools": ["fs.write"] // subtracted from the allowlist
}
}
```
Concurrency is bounded by the scheduler (`subagent.NewScheduler(2)` in `cmd/famclaw/main.go`). Each `spawn_agent` invocation gets a dedicated result channel β concurrent calls do not cross-deliver. The tool is parent-only (role-gated via `turn.Tools`) and has no MCP tool access unless the parent explicitly allowlists. Lives in `internal/subagent/`.
---
## Web fetch (`web_fetch`)
Off by default. When enabled, the LLM gets a `web_fetch` tool that retrieves a URL and returns extracted text β `text/html` is parsed via `golang.org/x/net/html` and stripped of ``/`<style>`/`<head>`; `text/plain` and `application/json` pass through. Useful for "what's the weather", "look up the docs page for X", and similar fetches.
Enable in `config.yaml`:
```yaml
tools:
web_fetch:
enabled: true
allowed_roles: [parent] # role gate β checked when registering the tool
url_allowlist: # REQUIRED β empty list denies all (SSRF guard).
- wikipedia.org # Subdomains of an allowed host match automatically.
- en.wikipedia.org
max_bytes: 262144 # 256 KB response cap
timeout_seconds: 15
```
Defense in depth:
- **Role gate** at registration β the tool is only added to the LLM's tool list for users in `allowed_roles`.
- **OPA `tool_policy` rule** at the tool loop β `parent` and `age_13_17` are allowed; `under_8` and `age_8_12` are denied. Blocked calls never dispatch.
- **URL allowlist** in `handleWebFetch` β only `http`/`https` schemes; the request host must equal an allowlist entry or be a subdomain of one. **An empty allowlist denies all fetches** (SSRF guard) β operators must list the hosts they trust. The same predicate is re-applied to every redirect target inside `webfetch.Fetch`.
- **Private-network block** in `internal/webfetch` β the dialer resolves DNS itself and rejects loopback / RFC1918 / RFC4193 ULA / link-local / multicast / unspecified IPs, so a misconfigured allowlist or DNS-rebinding trick can't reach the home LAN.
- **Size + timeout caps** in `internal/webfetch` β `MaxBytes` enforced via `io.LimitReader`, redirect chain capped at 5 hops, request `Timeout` from config.
The fetcher itself is in `internal/webfetch/`; the agent handler lives in `internal/agent/agent.go` (`handleWebFetch`).
---
## Security scanning
FamClaw uses [HoneyBadger](https://github.com/famclaw/honeybadger) to scan skills at two points:
**Install time.** `famclaw skill install <path>` scans with HoneyBadger before writing anything to disk. FAIL verdicts block the install by default.
**Runtime, asynchronously.** Tools used during a conversation are scanned in the background after the turn completes. If a scan fails, the tool is quarantined and filtered out of the next turn. This never adds latency β scanning runs in parallel with or after the response.
All behavior is configurable in `config.yaml` under the `seccheck:` section.
---
## Status
**v0.5.0 β first deployed family release.** v0.5.1 in flight (closes the bugs surfaced by the first real-world install).
### What works
| Feature | Status |
|---------|--------|
| **Policy gate** | OPA rules for input, tool calls, and output (33 Rego tests) |
| **Pipeline engine** | Composable stages: classify β policy β LLM β tools β output filter |
| **Multi-backend LLM** | OpenAI-compatible: Ollama, llama.cpp, Groq, OpenAI, OpenRouter |
| **Smart tool selection** | Token-budget-aware filtering, role+skill scoping |
| **Context compression** | Tiered truncation keeping system prompt + pinned messages |
| **Agent dispatch** | `spawn_agent` builtin tool β parent LLM delegates to a different profile (default-deny MCP tools, per-call timeout, scheduled with concurrency cap) |
| **Web fetch** | `web_fetch` builtin tool (off by default) β fetch a URL and return extracted text, role-gated + OPA `tool_policy` + per-host allowlist + size/timeout caps |
| **Skill adapters** | FamClaw (SKILL.md), OpenClaw (SOUL.md), Claude Code (.md) |
| **Skill install** | From parent dashboard Skills tab or CLI; HoneyBadger-scanned at install time |
| **llama.cpp sidecar** | Spawns llama-server, GGUF model catalog, TurboQuant support |
| **Security scanning** | Honeybadger runtime stage, install-time + stale scan gates |
| **Web UI** | Chat, parent dashboard, 5-step wizard with AI profiles, PIN-gated skill install/remove |
| **Web auth** | Cookie-based web sessions + machine-bound credential vault (`internal/credstore`, `internal/web/middleware`); see [docs/SECURITY.md](docs/SECURITY.md) |
| **Telegram + Discord** | Fully wired gateway bots, message chunking past per-platform limits (4096/2000 chars) |
| **Unknown-account backend** | Strangers messaging the bot are recorded against a parent-controlled queue, never auto-promoted to a user (issue #111 backend) |
| **MCP tools** | Multi-transport (stdio/HTTP/SSE), unified tool registry |
| **LLM profiles** | Multiple named endpoints, per-user assignment via wizard |
| **CI/CD** | CodeQL, govulncheck, SBOM, cosign signing, TruffleHog, race detector on gateway+agent, schema-drift gate, Telegram/Discord integration tests |
### Recommended models
| Hardware | Model | Why |
|----------|-------|-----|
| Mac Mini M1+ 16GB | `gemma4:e4b` | Native tool calling, multimodal |
| RPi 5 8GB | `gemma4:e2b` | Fits in 3GB Q4, tool calling |
| RPi 4 4GB | `qwen3:4b` | Best efficiency |
| RPi 3 | Use remote | Gateway only |
See [docs/BACKENDS.md](docs/BACKENDS.md) for inference engine comparison.
See [AGENTS.md](./AGENTS.md) for the full build plan.
---
## Testing
### Quick
```bash
CGO_ENABLED=0 go test ./... -count=1
opa test internal/policy/policies/family/ internal/policy/policies/data/ -v
```
### Integration
```bash
CGO_ENABLED=0 go test -tags integration ./e2e/... -count=1
```
REST stubs only β no real bots, no network.
### Behavioral (optional β needs local Ollama)
```bash
make behavioral
```
13 probeΓpersona pairs against the assembled system prompt.
### Schema golden
Regenerate the SQLite schema fixture:
```bash
UPDATE_SCHEMA_GOLDEN=1 go test ./internal/store/
```
### Prompt snapshots
Regenerate the four persona snapshots:
```bash
UPDATE_PROMPT_SNAPSHOTS=1 go test ./internal/prompt/
```
---
## License
[AGPL-3.0](./LICENSE)