Skip to content

Concepts

Privacy

Local-first by default. What stays on your machine, what gets mirrored, and how to lock it down further.


aiperson is local-first. Your persona is in a git repo you own. Your corpus is a SQLite file on your laptop. We host nothing you didn’t ask us to.

What stays local

By default, everything. The relay’s role is auth, GitHub App brokerage, and synthesis — not a duplicate of your conversations.

Optional mirror

A subset of corpus events — those with allow_relay_mirror = true — can be pushed to the relay’s Postgres for cross-device sync. The per-kind default is:

Kindallow_relay_mirror default
git_event, task_event, plan_event, repo_state_eventtrue
claude_session (metadata only)true
chat_prompt, thread_turn, tool_call, tool_resulttrue
reading_list_entrytrue
email_body, sms, notes_bodyfalse
calendar_event_description, chatgpt_messagefalse
config_eventfalse
screenshotfalse
voice_capturefalse

Override per-kind under /dashboard/privacy.

Messages mirror policy

Browser-extension thread_turn observations carry metadata.{role, conversation_id, external_message_id, url} and are mirrored by default — that’s what makes “your AI remembers across devices” a true statement. The relay fans each captured turn into:

You can flip mirroring off per-surface in the popup, or globally under /dashboard/privacy. The full message bodies are written to your local messages table regardless of the mirror flag, so capture works even when the relay is unreachable or you’ve turned mirroring off.

Dignity controls in the browser

On every supported cloud chat surface (21 of them today — ChatGPT, Claude, Gemini, Copilot, Grok, Meta, Perplexity, Mistral, HuggingChat, Poe, Pi, Lmarena, plus Kimi, DeepSeek, Qwen, Doubao, ChatGLM, Wenxin, Yi, Hailuo, SenseChat), four controls give you the driver’s seat:

  1. Master kill switch in the popup — pauses every surface instantly.
  2. Per-conversation skip — the in-page indicator (bottom-right, on every captured surface) is a one-click toggle for that one chat. Flips to ⏸️ until you flip it back.
  3. Regex redactor — user-defined patterns are applied before the turn leaves the page. Invalid regex is flagged in the popup and never reaches the capture path. Stacks with the relay-side secret-redaction patterns documented below.
  4. Per-surface health dots — green (≤5 min since last accepted turn), yellow (≤60 min), red (otherwise or on error). Visible in the popup AND on the dashboard Overview via the relay’s /v1/me/capture-health endpoint.

A 401 from the relay wipes the cached ID token and surfaces a “Sign in again” CTA — capture never re-queues behind a permanently-failing handshake.

Secret redaction

Every harvested payload passes through secret_redact() before any write. Patterns matched:

  1. Quoted env-style: API_KEY="…"
  2. Unquoted env-style: API_KEY=…
  3. Prefix tokens: gh[pousr]_…, sk-…, xox[abprs]-…, github_pat_…
  4. Authorization headers: Authorization: Bearer …
  5. PEM blocks: -----BEGIN […]-----…-----END […]-----

Redaction applies to both event payloads and message contents. Add your own patterns under /dashboard/privacy, and (for cloud captures specifically) in the extension popup’s “Privacy controls” textarea — the latter applies in-browser, before the turn ever leaves the page.

Signed snapshots

The corpus::snapshot API produces signed JSONL exports (entities / relations / events / provenance + manifest signed by your Ed25519 key). The same key signs every .person.json commit. Round-trip verification proves byte-equal recovery.

Portable export

personkit export --format=markdown emits the whole corpus as Obsidian-ready .md files — one per thread, with YAML front-matter. You own these files outright; dotperson keeps no claim on them. Move them, version-control them, leave the product entirely — the data is yours.

Wiping

What dotperson cannot see