Before you begin
- A computer running macOS, Linux, or Windows.
- Node.js 22 or newer. Node.js 24 LTS is recommended.
- A model API key. The generated default configuration uses Link API.
The WebUI is Familiar's home and the only interface you need. Chat platforms like Discord and QQ are optional add-ons covered in Connect chat platforms.
Install Familiar
macOS or Linux
Open Terminal and run:
curl -fsSL https://raw.githubusercontent.com/qearlyao/familiar/main/scripts/install.sh | sh
Windows
Open PowerShell and run:
irm https://raw.githubusercontent.com/qearlyao/familiar/main/scripts/install.ps1 | iex
The installer checks Node.js and npm, installs Familiar, and creates your workspace at ~/.familiar. You do not need to run familiar init afterward.
Add your model key
Open the .familiar folder in your home directory:
- macOS: In Finder, press
Command + Shift + G, enter~/.familiar, and press Return. - Windows: Paste
%USERPROFILE%\.familiarinto the File Explorer address bar. - Linux: Show hidden files in your file manager, then open
.familiarin your home folder.
Open .env in a text editor and fill in the model key line:
ANTHROPIC_API_KEY=paste-your-link-api-key-here
With the generated default configuration, your Link API key goes after ANTHROPIC_API_KEY=. The name comes from the model's Anthropic-compatible credential slot.
Leave the other .env lines and the rest of config.toml unchanged for now. If you want to add Discord or QQ, do that later in Connect chat platforms.
Make Familiar yours
Do this before the first launch. SOUL.md and USER.md become part of Familiar's core instructions (the system prompt), so the first reply can already sound like the companion you intended.
SOUL.md: who Familiar is
Replace the defaults with a name, voice, temperament, values, boundaries, and the kinds of things you want your companion to notice. The WebUI reads the companion's name from this exact field:
- **Name:** [companion name]
Keep the **Name:** label and change only its value. Keep the other parts of the template that fit; rewrite the parts that do not.
USER.md: who Familiar knows
Add your name, current priorities, important people, response preferences, recurring difficulties, and what you want help remembering. Do not store passwords, API keys, or other secrets here.
MEMORY.md: durable context
Familiar updates this file with facts worth carrying across conversations. You can review or correct it, but you do not need to fill it before the first launch.
CONTACT.md: a private name for you
This optional one-line file is the private nickname Familiar keeps for you, like a contact-book entry. You can write or change the name yourself, or leave it blank and ask your companion to choose a name for you.
HEARTBEAT.md: what to do while awake
This is the action menu Familiar uses during an idle-triggered heartbeat. Review its suggestions before enabling heartbeat, especially whether Familiar may reach out, write a diary entry, pursue a curiosity, or sit the turn out.
SOUL.md and USER.md are not profiles shown after onboarding. They are core context Familiar reads when deciding how to speak and respond.
Start Familiar
Open a fresh Terminal or PowerShell window and run:
familiar run
Keep this window open while you use Familiar. A successful start prints messages similar to:
Web side-door listening on http://127.0.0.1:8787
familiar running for workspace ...
Open the WebUI at http://127.0.0.1:8787 on the same computer. Tailscale is not required for local access.
Hello. A normal reply means the installation, your model key, and model access are all working.
Press Ctrl + C in the terminal to stop Familiar. After changing .env, stop Familiar and run familiar run again.
Use the WebUI on your phone
There are two ways to reach Familiar from another device, and they work at the same time. With Tailscale, one address works both at home and away, so nothing needs to be switched when you leave or come back. The local-network option is for devices without Tailscale, and only works at home.
Recommended: one address everywhere with Tailscale
Tailscale gives your phone a private connection to the computer running Familiar. When both devices are on your home network, the connection travels directly over the LAN; when you are away, it travels through your private tailnet. You open the same address either way, so one bookmark or home-screen app keeps working wherever you are. This does not expose Familiar to the public internet.
- On the home computer, download Tailscale from the official download page (macOS, Windows, and Linux installers are listed there) and install it.
- On your phone, install the Tailscale app from the App Store (iPhone/iPad) or Google Play (Android).
- Open Tailscale on both devices and sign in with the same account (Google, Apple, Microsoft, or GitHub all work). Signing in creates your private tailnet; two devices on the same account can reach each other by default.
- Check that both devices show as connected — the Tailscale app lists every device in your tailnet. If you have customized tailnet access rules (ACLs), make sure they allow the phone to reach the home computer; a fresh account needs no changes.
- On the home computer, run:
tailscale serve --bg http://127.0.0.1:8787
tailscale serve status
Open the HTTPS address shown by tailscale serve status on the phone, at home or away. No config.toml change is needed: Tailscale forwards to Familiar on the computer itself, so bind_address can stay at its default 127.0.0.1 and nothing extra is opened to your network. Keep the computer awake with both Tailscale and Familiar running. See the Tailscale Serve reference for other Serve options.
Do not use tailscale funnel for this private setup. Tailscale ACLs decide which devices can reach the computer; the optional Familiar bearer login below adds a second login boundary.
Without Tailscale: your local network
Use this for a phone or laptop that does not run Tailscale and is on the same Wi-Fi or wired LAN as the computer. It does not provide access when you are away from home.
Open config.toml and change bind_address in its existing [web] section:
[web]
port = 8787
bind_address = "0.0.0.0"
Restart Familiar after saving. If your computer asks about firewall access, allow private or local networks only. Then, from the nearby device:
- Make sure the phone and computer are on the same Wi-Fi network.
- Find the computer's local IP address in its network or Wi-Fi settings. It usually looks like
192.168.x.x. - On the phone, open
http://192.168.x.x:8787, replacing the example IP with the computer's address.
0.0.0.0 is the address Familiar listens on, not an address to open in the phone's browser. It makes the WebUI available to other devices on the network, so use this only on a home network you trust.
The two setups are independent and can be combined: bind_address = "0.0.0.0" does not interfere with Tailscale, and coming home or leaving never requires changing it. If every remote device runs Tailscale, you do not need 0.0.0.0 at all.
Optional: require a login secret
You can skip this on a trusted home network. For Tailscale, it is optional defense-in-depth; use it if you do not want every permitted tailnet device to open the WebUI automatically. If the computer uses a shared or public network, either return bind_address to 127.0.0.1 or protect the WebUI with bearer login.
Add a long password to .env:
FAMILIAR_WEB_BEARER_TOKEN=choose-a-long-random-password
Then change these lines in the existing [web] section of config.toml and restart Familiar:
auth_mode = "bearer"
bearer_token = "${FAMILIAR_WEB_BEARER_TOKEN}"
Install Familiar on the home screen
- iPhone or iPad: Open Familiar in Safari, tap Share, then Add to Home Screen.
- Android: Open Familiar in Edge or Chrome, open the browser menu, then choose Install app or Add to Home screen.
The home-screen app still connects to Familiar on your computer, so that computer and familiar run must remain available. Some browsers require HTTPS for a full PWA installation; over a local http:// address, they may add a home-screen shortcut instead.
Let Familiar wake up on its own
Heartbeat is optional and disabled for new workspaces. Once the first conversation works, customize HEARTBEAT.md, then enable the scheduler in config.toml.
When a heartbeat becomes due, Familiar starts an agent turn and points the companion to HEARTBEAT.md as its menu. The companion can proactively message you, reflect in its diary, pursue a curiosity with available tools, or choose to stay silent.
Choose what waking up means
Open HEARTBEAT.md and review each section. Remove actions you do not want, add boundaries, and write the instructions in a voice that fits the companion.
Enable heartbeat and set the timing
Open config.toml and set:
[heartbeat]
enabled = true
idle_threshold_minutes = 60
interval_minutes = 240
idle_threshold_minutesis how long the owner must be idle before the first heartbeat becomes eligible.interval_minutesis the minimum time between later heartbeats while the owner remains idle.- Only owner messages reset the idle timer. Familiar's replies and tool work do not.
Save the file and restart Familiar if it is already running. With the example above, the first heartbeat becomes eligible after 60 minutes of owner inactivity; later heartbeats can repeat every 240 minutes until the owner sends another message.
Connect chat platforms (optional)
Familiar lives in the WebUI by default. If you also want it in Discord or QQ, connect one or both — the same companion, memories, and sessions carry across every platform. Each platform has an enabled switch; set it to false to stop that platform connecting without deleting its config. The WebUI is always on and cannot be disabled.
Discord
- Open the Discord Developer Portal and select New Application.
- Open Bot, create the bot, then select Reset Token and copy the token. Treat it like a password.
- On the same page, enable Message Content Intent.
- Open OAuth2 > URL Generator. Select the bot scope, then allow Send Messages, Read Message History, and Attach Files.
- Open the generated URL and invite the bot to your private server.
- In Discord, open User Settings > Advanced and enable Developer Mode.
- Right-click your own profile and select Copy User ID.
Add the bot token to .env:
DISCORD_TOKEN=paste-your-bot-token-here
Then set your user ID in the [discord] section of config.toml:
[discord]
enabled = true
owner_id = "paste-your-discord-user-id-here"
Familiar ignores Discord server channels unless you allow them. With Developer Mode enabled, right-click a server text channel, select Copy Channel ID, and add the ID to allowed_channels:
allowed_channels = ["paste-channel-id-here"]
Add more IDs inside the brackets, separated by commas. Make sure the bot can view and send messages in each channel, then restart Familiar. The generated configuration uses channel_trigger = "always"; change it to "mention" if you want Familiar to respond only when someone mentions the bot.
QQ (OneBot 11)
Familiar connects to any OneBot 11 server's forward WebSocket, so NapCat and Lagrange.OneBot are interchangeable. Set up the server first, then point Familiar at it. Two accounts are involved and they are different: the bot account (a dedicated small account that logs into the OneBot server) and your own QQ number in owner_id (the human whose DMs Familiar responds to).
1. Install the OneBot server (NapCat)
Windows — use the manual Shell package, not the one-key installer:
- Download
NapCat.Shell.zipfrom the NapCat releases page and extract it. (TheNapCat.Shell.Windows.OneKey.zipinstaller currently fails with a 404 — see troubleshooting below.) - Install the latest QQ and log in once normally.
- Double-click
launcher.bat(Windows 10:launcher-win10.bat). To log straight into an account you have used before, pass its number:launcher.bat -q 123456789.
Linux (VPS) — run the installer over SSH:
curl -o napcat.sh https://nclatest.znin.net/NapNeko/NapCat-Installer/main/script/install.sh \
&& sudo bash napcat.sh --docker n --cli y --proxy 0
--docker n installs the Shell version, which stores the login session on disk under ~/Napcat so you only scan the QR code once. --cli y adds the napcat TUI for configuring from a terminal. The Docker image works too but does not persist your login unless you bind-mount its data directories.
The Shell version runs in the background with screen, which does not survive a reboot or restart after a crash on its own. Add a systemd user service so it comes back automatically:
# ~/.config/systemd/user/napcat.service
[Unit]
Description=NapCat (QQ OneBot server)
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
ExecStart=/bin/bash -c 'xvfb-run -a <QQ_EXECUTABLE> --no-sandbox -q 123456789'
Restart=always
RestartSec=10
[Install]
WantedBy=default.target
Copy <QQ_EXECUTABLE> and the -q argument from the startup command the installer prints at the end, then enable it and allow it to run while logged out:
systemctl --user daemon-reload
systemctl --user enable --now napcat
loginctl enable-linger $USER
loginctl enable-linger is required — without it the user service stops when your SSH session ends.
2. Log in and add a WebSocket server
NapCat's WebUI listens on port 6099. The login token is printed in the startup log as WebUi User Panel Url: http://127.0.0.1:6099/webui?token=... (also in config/webui.json). On a remote VPS, forward the port first: ssh -L 6099:127.0.0.1:6099 user@vps, then open the URL locally.
- Log in by scanning the QR code with the QQ mobile app. NapCat will ask you to set a WebUI password on first use.
- Under network config, add a WebSocket server on port 3001 bound to
127.0.0.1. - Set
messagePostFormattoarray— Familiar only parses segment arrays, not CQ strings. - Leave the token empty for a same-machine setup; set one if the WebSocket is exposed to a network.
3. Point Familiar at it
Add the [qq] section to config.toml:
[qq]
enabled = true
ws_url = "ws://127.0.0.1:3001"
owner_id = "your QQ number"
allowed_groups = []
If the OneBot server has an access token, put it in .env:
QQ_ONEBOT_TOKEN=paste-your-onebot-token-here
Non-owner DMs and groups outside the allowlist are ignored. Use a dedicated small account rather than your main QQ, keep it logged in from one place only, and let it idle a few days before adding it to groups.
Optional: add more capabilities
These are not required for your first conversation. Add only the credentials for features you want to use, then restart Familiar.
ElevenLabs voice replies
Create an API key in ElevenLabs API keys, choose a voice, and add its voice ID alongside the key in .env:
ELEVENLABS_API_KEY=paste-your-elevenlabs-api-key
ELEVENLABS_VOICE_ID=paste-your-voice-id
Groq voice transcription
Create a key in the Groq API Keys dashboard, then add it to .env. Familiar uses it to transcribe incoming audio:
GROQ_API_KEY=paste-your-groq-api-key
Web search and page fetching
Use Tavily for web search and TinyFish for page fetching. Add either or both keys to .env:
TAVILY_API_KEY=paste-your-tavily-api-key
TINYFISH_API_KEY=paste-your-tinyfish-api-key
Image generation
The generated configuration uses Link API image models. Add your Link API key to .env; you can reuse the same key you entered for the default chat model:
LINK_API_KEY=paste-your-link-api-key
To give Familiar visual references for people, characters, outfits, or other recurring subjects:
- Create
ref-imagesinside your Familiar workspace. The default location is~/.familiar/ref-images. - Place your reference image files in that folder.
- Open
~/.familiar/skills/image-gen/SKILL.mdand find Reference Images. - Replace the entire placeholder list with the exact filename and a short description for each of your images.
Available refs:
- `person-face.jpg` - clear close-up portrait
- `person-full-body.png` - full-body reference and usual outfit
The filenames in the bundled skill are examples only. Remove them and add your real files; entries that do not match files in ref-images cannot be used. Clear descriptions help Familiar choose the best one to three references for a scene.
Browser control
Run the installer again with the browser option to add OpenCLI and browser-harness.
macOS or Linux:
curl -fsSL https://raw.githubusercontent.com/qearlyao/familiar/main/scripts/install.sh | sh -s -- --with-browser
Windows PowerShell:
& ([scriptblock]::Create((irm https://raw.githubusercontent.com/qearlyao/familiar/main/scripts/install.ps1))) -WithBrowser
Install the OpenCLI browser extension, then change these existing lines under [browser] in config.toml:
[browser]
enabled = true
Upgrade Familiar
When a new version is available, stop Familiar and run:
familiar upgrade [--with-opencli]
This updates Familiar, then adds any missing workspace defaults without overwriting your existing configuration, persona files, or skills. Add --with-opencli when the OpenCLI browser helper should also be upgraded. Start Familiar again with familiar run, or use familiar restart if you installed it as a service.
If something goes wrong
familiar is not found
Close and reopen the terminal. If it still fails, check that npm's global bin directory is on your PATH.
Discord doesn't connect
Confirm the file is named exactly .env, is inside ~/.familiar, and contains the DISCORD_TOKEN=... line. Discord is optional — without a token, Familiar still runs and the WebUI is the whole interface.
Discord reports disallowed intents
Enable Message Content Intent in the Discord Developer Portal, then restart Familiar.
The bot ignores your DM
Confirm owner_id is your user ID, not the bot ID or application ID.
The bot starts but cannot answer
Recheck the Link API key after ANTHROPIC_API_KEY= in .env.
QQ: the NapCat one-key installer returns a 404
NapCatInstaller.exe pins a QQ download URL (QQ9.9.19.34231) that Tencent has removed, so the one-key package fails on download. Use NapCat.Shell.zip instead, which needs you to install QQ yourself.
QQ: NapCat asks you to log in every launch
Quick login only happens when you pass the account number with -q; without it NapCat defaults to QR login even if a session exists. Start with launcher.bat -q 123456789.
QQ: sent messages never arrive
A freshly logged-in account is throttled by QQ anti-spam — the send reports success but the other side sees nothing. Wait a day or two and test with a real person, not just the bot account.
QQ: everything looks right but nothing connects
Check messagePostFormat is array, and confirm the ws_url port matches the WebSocket server you added in the WebUI (not the 6099 WebUI port).