Skip to content

Self-hosting Khiip

Khiip is self-hosted by design — the daemon runs entirely on your machine, against your own accounts and rate-limit budgets, and your data stays in your filesystem. There is no hosted capture service.

Install

Today Khiip installs from source (PyPI publish is on the roadmap):

Terminal window
git clone https://github.com/KhiipAI/khiip.git ~/projects/khiip
cd ~/projects/khiip
pip install -e ".[dev]"

Requires Python 3.10+. See Installation for per-source credentials.

Run the daemon

Terminal window
khiipd serve # 127.0.0.1:8478 by default
khiipd serve --host 0.0.0.0 --port 8478 # bind on your LAN (see the security note below)

The daemon stays in the foreground. To keep it running:

  • Quick/dev: khiipd serve & (backgrounds it in the current shell)
  • Durable: run it under your OS process manager so it restarts on boot/crash — see Run as a managed service below.

Run as a managed service

For a daemon that restarts on boot or crash, run khiipd serve under your OS process manager. Find the absolute path to khiipd first with which khiipd — neither systemd nor launchd inherits your interactive shell PATH, and a virtualenv install puts the binary under that env’s bin/. Keep your per-source credentials in ~/.config/khiip/config.toml rather than environment variables: the daemon reads that file no matter how it’s launched, which sidesteps the fact that service managers don’t inherit your shell environment. (KHIIP_HOME is a dev/test override only — production services should not set it.)

Linux — systemd user service

Write ~/.config/systemd/user/khiip.service:

[Unit]
Description=Khiip capture daemon
After=network-online.target
Wants=network-online.target
[Service]
ExecStart=%h/.local/bin/khiipd serve
Restart=on-failure
RestartSec=5
[Install]
WantedBy=default.target

Replace ExecStart with your real which khiipd path (e.g. a virtualenv’s bin/khiipd), then enable it:

Terminal window
systemctl --user daemon-reload
systemctl --user enable --now khiip # start now, and on every login
loginctl enable-linger "$USER" # keep running without an active login session
systemctl --user status khiip # confirm it's up
journalctl --user -u khiip -f # follow logs

macOS — launchd agent

Write ~/Library/LaunchAgents/ai.khiip.daemon.plist (replace the /Users/you/… paths):

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>ai.khiip.daemon</string>
<key>ProgramArguments</key>
<array>
<string>/Users/you/projects/khiip/.venv/bin/khiipd</string>
<string>serve</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
<key>StandardOutPath</key>
<string>/Users/you/Library/Logs/khiip.log</string>
<key>StandardErrorPath</key>
<string>/Users/you/Library/Logs/khiip.err.log</string>
</dict>
</plist>

Then load it:

Terminal window
launchctl load ~/Library/LaunchAgents/ai.khiip.daemon.plist # start now, and on login
launchctl list | grep khiip # confirm it's loaded
tail -f ~/Library/Logs/khiip.log # follow logs
launchctl unload ~/Library/LaunchAgents/ai.khiip.daemon.plist # stop

Both services bind 127.0.0.1:8478 by default. To reach the daemon from another machine, add --host 0.0.0.0 to the serve arguments and read the binding caution above first.

Where your data lives

WhatDefault pathNotes
Config + auth token~/.config/khiip/config.toml + auth.toml (the API key)
SQLite index~/.local/share/khiip/index.dbderived cache (vault is canonical; a rebuild-from-vault command is planned — back it up for now, see below)
Vault (Markdown captures)~/khiip-vault/canonical — your source of truth
Source-tier raw bytes[storage] data_root (defaults under ~/.local/share/khiip/)gzipped originals; insurance against upstream rot

See Configuration for overrides.

Cross-machine sync

Khiip has no sync server — you bring your own. Point the vault and data_root at synced storage:

[daemon]
vault_path = "~/Library/Mobile Documents/com~apple~CloudDocs/khiip-vault" # iCloud, e.g.
[storage]
data_root = "/Volumes/SSD/khiip-data" # external SSD / Dropbox / network mount

Run the daemon on one machine at a time against a given vault to avoid write conflicts.

Backup

Because the vault is canonical and the index is derived, a minimal backup is:

  1. ~/khiip-vault/ — your captures (Markdown + frontmatter). The important one.
  2. data_root — the Source-tier raw bytes, if you want the originals preserved.
  3. ~/.config/khiip/auth.toml — the API key (or just rotate it after a restore with khiipd auth rotate).

Also back up ~/.local/share/khiip/index.db for now. By design (ADR-0009) it’s a derived cache reconstructable from the vault — a khiipd rebuild-index command is planned for exactly that — but that command isn’t shipped yet, so don’t rely on regenerating it. After any restore, run khiipd validate to check vault ↔ index consistency.

Automating it

A vault backup is just a file copy, so any scheduler works. A nightly rsync to an external disk via cron, for example:

Terminal window
# crontab -e → run at 02:30 daily
30 2 * * * rsync -a "$HOME/khiip-vault/" /Volumes/Backup/khiip-vault/

Add your data_root to the same job if you want the Source-tier originals mirrored too.

Upgrading

Terminal window
cd ~/projects/khiip
git pull
pip install -e ".[dev]" # picks up new/updated deps
khiipd validate # sanity-check the vault ↔ index after upgrade

Roadmap

  • PyPI publish (pip install khiip) — planned for the public launch
  • Docker image + compose — planned; not yet available (install from source for now)