Skip to content

Operate

Troubleshooting

Daemon not running, embeddings stuck at zero, extension says "not signed in" — and the actual fixes.


Run personkit doctor first — it diagnoses most of what’s below. The rest of this page is the common dead-ends with explicit fixes.

”Last event was N days ago”

Reported by personkit doctor and the corpus health output.

Cause. The harvester daemon isn’t running. Pre-v0.3 builds shipped a launchd job for observers only; harvesters had to be invoked manually.

Fix.

personkit daemon --install
launchctl list | grep one.aiperson.personkit-daemon   # confirm loaded
tail -f ~/.dotperson/daemon.out.log                    # watch the first cycle

If the job won’t load, the install path prints the manual launchctl load command and points you here.

”Embeddings: 0” in corpus health

Cause. No embedder configured. Vec retrieval degrades to BM25-only; FTS still works.

Fix. Pick one:

Then backfill the existing events:

personkit corpus embed --max 20000

The daemon drains pending embeddings on every cycle once an embedder is configured.

”Browser extension says: not signed in”

Cause. The dashboard handed back a token to the extension that has since expired (Firebase ID tokens live ~1h; the extension lazily refreshes via the dashboard handoff).

Fix. Click “Sign in” in the popup; the dashboard tab will re-mint a fresh token via externally_connectable and the popup will live-update.

If the dashboard never returns the token, check that the dashboard origin is https://aiperson.one and the extension has externally_connectable.matches containing it (it does, by default). If you’re testing on a different domain, add it to the manifest.

”Daemon is running but nothing new is showing up”

personkit doctor reports the daemon as loaded, but corpus health doesn’t change.

Possible causes.

  1. Harvesters disabled. Check ~/.dotperson/harvesters/enabled.json. Reset with personkit harvest enable <id> for each one (or delete the file — default-on).
  2. No sources detected. personkit harvest run-once shows each harvester’s is_present() decision. If the source path doesn’t exist (no ~/.claude/projects/, no git repos in the watched list), the harvester skips.
  3. Watermark stuck. A bug-in-progress can leave a watermark JSON at ~/.dotperson/harvesters/<id>.json reporting “already up-to-date” forever. Delete the file to force a re-scan.

”MCP host says: tool not found”

Symptom: Claude Code / Cursor / etc. doesn’t see read_persona or corpus_query.

Cause. The MCP server isn’t wired into the host’s config, or npx -y -p @aiperson/mcp-server@latest dotperson-mcp is failing.

Fix.

personkit connect --tool claude_code     # or cursor / vscode / windsurf / …
personkit verify surfaces                 # runs a stdio MCP smoke against every wired host

If verify surfaces fails with spawn dotperson-mcp ENOENT, your host doesn’t inherit shell PATH. Set PERSONKIT_BIN to the absolute path of personkit in your shell config and reconnect.

”Browser extension doesn’t capture anything”

Cause. Capture is opt-in per surface. The popup shows a per-surface toggle for each of the 21 wired chat surfaces; every one is off by default until you click it. (Chinese-frontier surfaces — Kimi, DeepSeek, Qwen, Doubao, ChatGLM, Wenxin, Yi, Hailuo, SenseChat — additionally sit behind an “Experimental surfaces” master flag.)

Fix. Flip the toggle for each surface you want covered. Refresh the chat tab. Check the popup’s per-surface health dot — green within five minutes of the next turn means it’s landing. From the terminal:

personkit corpus surfaces                          # confirm the surface appears
personkit corpus messages --surface=browser-ext:chatgpt --limit=5

If the dot stays red and the popup shows non-zero “rejected” counts, capture is reaching the relay but the relay is rejecting it — usually a stale extension version (refresh the unpacked extension or wait for the Chrome Web Store update). If the dot is red AND rejected is zero, the extension never reached the relay — check the popup for a “Sign in again” banner (a 401 wipes the token rather than re-queuing indefinitely).

”Synthesis pass keeps reporting threads_summarised: 0

Cause. No threads in the window. The daily brief and synthesis read the V2 threads table; if your only capture is via the legacy events (kind = claude_session etc.) and you haven’t upgraded claude_sessions to emit messages, the threads table stays empty.

Fix. Upgrade. The v0.3+ claude_sessions harvester emits both — re-run personkit harvest run-once --id claude_sessions and re-check corpus health.

”Relay sync push failed: 401”

Cause. ID token expired and refresh failed (often because the Firebase refresh token was rotated server-side).

Fix.

personkit login

Re-runs the GitHub → Firebase flow, writes fresh credentials, restarts sync on the next daemon cycle.

Resetting from scratch

If something is so off you want to start over:

# Archive first — two formats, your choice:
personkit corpus snapshot --out ~/dotperson-archive            # signed JSONL (round-trippable)
personkit export --format=markdown --out ~/dotperson-archive-md   # plain markdown (Obsidian)

# Then wipe — pick how thorough:
personkit corpus wipe --keep-persona       # just the corpus DB; credentials + persona cache stay
personkit corpus wipe                      # corpus + harvester/observer state + persona cache
personkit uninstall --yes                  # full uninstall: also removes the daemon plist

# Re-run setup:
personkit setup
personkit daemon --install

Your persona repo on GitHub survives — it’s yours. Restore the corpus from an archive any time with:

personkit corpus restore --from ~/dotperson-archive

Reporting bugs

If none of the above match, capture context:

personkit doctor --errors --since 1d > /tmp/diag.txt
personkit corpus health --json >> /tmp/diag.txt
tail -200 ~/.dotperson/daemon.err.log >> /tmp/diag.txt

Open an issue with /tmp/diag.txt at github.com/humphreytheodore/personkit/issues.