Work from symptoms to cause. Each section links to the relevant log file under ~/.openchronicle/logs/.
Symptom: openchronicle start returns Already running (pid N) but the process is dead.
Check:
ps -p $(cat ~/.openchronicle/.pid) || rm ~/.openchronicle/.pid
openchronicle startA stale PID file is the typical cause; stop removes it cleanly, crashes don't.
Symptom: foreground start immediately exits without error.
openchronicle start --foregroundRead the console output. Common culprits:
OSError: [Errno 48] Address already in use→ another process holds port 8742.lsof -i :8742to find it.- Missing
OPENAI_API_KEY→ set it or putapi_key = "..."in[models.default]. mac-ax-helper/mac-ax-watcherbinary missing → runbash resources/build-mac-ax-helper.sh && bash resources/build-mac-ax-watcher.sh.
Most common cause: Accessibility permission not granted to the terminal you launched from.
openchronicle capture-once
cat ~/.openchronicle/capture-buffer/*.json | jq '.ax_tree | length' | headIf the tree is {} or tiny across the board, open System Settings → Privacy & Security → Accessibility and enable your terminal (Terminal, iTerm2, Warp, VS Code…) plus openchronicle itself if it appears. Restart the daemon.
Second most common cause: ax_depth too shallow for Electron apps. See capture.md.
Entries land in ~/.openchronicle/memory/event-YYYY-MM-DD.md at session boundaries. Silence usually means one of three things.
Check session.log:
tail -30 ~/.openchronicle/logs/session.logIf there's a single session started line but no session ended, the cutter thinks you're still in one session. Normal during continuous work. Force a boundary for debugging by pausing briefly (openchronicle pause, wait > session.gap_minutes, resume).
Check timeline.log:
tail -30 ~/.openchronicle/logs/timeline.logIf you see window scans but no production, it's usually one of:
- No captures in the window. The timeline skips empty windows. Confirm captures exist:
ls ~/.openchronicle/capture-buffer/ | wc -l. - LLM call failing. Look for
timeline aggregator failed. Check[models.timeline]config.
The reducer handles empty timelines gracefully — it marks the session reduced with no entry. If all your sessions end up with empty timelines, the aggregator is the root cause.
Check writer.log:
tail -50 ~/.openchronicle/logs/writer.logLook for reducer failed (retry N/5) lines. After 5 failed attempts the reducer writes a heuristic entry tagged heuristic and marks the session reduced — you should never see a permanently-stuck session.
Force a catch-up pass:
openchronicle writer runThis runs the same code path the daily 23:55 cron uses.
This is often correct behavior — the classifier's default action is an empty commit. It should only write when it sees a fact that would still matter in six months.
Signs it's misbehaving rather than doing its job:
classifier ended without commit at iter Ninwriter.log— the model bailed without callingcommit. Usually means the stage model is too weak to follow the tool-call protocol. Try a stronger[models.classifier].forbidden: classifier cannot write to event-*— the classifier tried to write back to an event-daily file. This is always rejected. If every session triggers it, the classifier prompt isn't landing; check thatclassifier.mdexists undersrc/openchronicle/prompts/.- Classifier writes duplicates every session — the stage model is skipping its
search_memorydedup check. Upgrade the model, don't add code.
Check timeline.log:
tail -30 ~/.openchronicle/logs/timeline.logIf you see window scans but no production, the aggregator window is empty. The fallback heuristic still produces something, so total silence means the tick itself isn't firing.
Force a scan:
openchronicle timeline tick
openchronicle timeline list -n 5Symptom: Claude Code / Cursor reports the server unreachable.
-
Is the daemon running?
openchronicle status curl -s http://127.0.0.1:8742/mcp -XPOST -H 'Content-Type: application/json' -d '{}' | head -5
-
Is
mcp.auto_start = trueandmcp.transport∈ {sse,streamable-http}?openchronicle config | grep -A3 '\[mcp\]'
-
Did
install claude-codeactually add the entry?claude mcp list | grep openchronicle
If mcp.auto_start = false, the daemon intentionally won't host a server; use stdio instead.
Symptom: you pasted http://127.0.0.1:8742/mcp into ChatGPT's Create Connector dialog and got "could not reach server" or "invalid URL."
ChatGPT's MCP client runs in OpenAI's cloud, not on your Mac — localhost is unreachable from its side. You need a public HTTPS URL via a tunnel (ngrok / Cloudflare Tunnel). See mcp.md → ChatGPT Desktop for the full setup, including the data-egress trade-offs. No amount of local config can make this work directly; the tunnel is mandatory. If you want a ChatGPT-style client that speaks to the local endpoint, Codex CLI works natively.
Symptom: Claude Code / Cursor / ChatGPT is attached, but when you ask "when is my interview?" it says "I don't know" instead of calling search or list_memories.
Two levers:
- Restart the client. MCP
instructionsand tool descriptions are only re-read on reconnect. After updating OpenChronicle, restart the client session. - Nudge once. Tell the client explicitly: "check openchronicle for my interview time." A single prompt usually anchors subsequent turns.
Symptom: ask "what code did I write in main.py at 14:30?" and the agent paraphrases from the event-daily sub_task ("edited main.py") instead of reading the actual code.
Cause: the agent isn't reaching for the raw-capture layer. Either it stopped at search / read_memory (compressed), or its session pre-dates the drill-down surface.
Fixes:
- Check the reducer is emitting breadcrumbs. Every sub_task should end with
— raw: read_recent_capture(at="HH:MM", app_name="…"). Open today'sevent-YYYY-MM-DD.mdand verify. If a line has no breadcrumb, the reducer's output didn't match the canonical[HH:MM-HH:MM, <app>]prefix — checklogs/writer.logfor the reduced entry text. - Try
search_capturesdirectly. Ask the agent "search captures for " or "what's in current_context". If those work, the FTS index is healthy and the issue is tool-selection, not retrieval. - Rebuild the captures index if it's empty or out of date. Run
openchronicle rebuild-captures-index. CompareSELECT COUNT(*) FROM capturesagainstls ~/.openchronicle/capture-buffer | wc -l— they should match modulo one active capture. - Restart the client after updating OpenChronicle — server-level
instructions(which teach the two-layer model) are only read on reconnect.
Symptom: a real 3-hour focused-work session produced two event-daily entries with a mid-session boundary.
Cause: session.max_session_hours (default 2) force-cut it. Raise to 4 in [session] if this is routine for you. Keep it finite — a runaway session is worse than a clean split.
Symptom: event-daily has many short entries for what was clearly one focused stretch.
Two likely causes:
session.soft_cut_minutestoo aggressive. You're single-apping for >3 min (say, a long read in the browser). Raise to 5–10.session.gap_minutestoo short. Idle stretches during thinking are ending sessions. Raise to 8–10.
The frequent-switching exception (≥2 distinct apps in the last 2 min) already defuses the soft cut for multi-app work — if you're still seeing cuts, one of the above two is the knob.
Symptom: laptop fan spinning during capture activity.
Tuning levers, in order:
same_window_dedup_seconds = 15.0(up from 5.0) — cuts re-capture rate during long typing in a single document.debounce_seconds = 5.0(up from 3.0) — batches more keystroke events.min_capture_gap_seconds = 5.0— hard-limits capture rate.include_screenshot = false— screenshots are the heaviest single cost per capture.ax_depth = 50— if you don't need deep Electron content.
Restart the daemon after any [capture] change.
Cause: the index drifted from disk (manual edits without rebuild-index, power loss mid-write, bug).
Fix:
openchronicle rebuild-indexRewrites entries, files, and entries_fts from the Markdown on disk. Idempotent.
Start from scratch without reinstalling:
openchronicle stop
openchronicle clean all -y # keeps config.toml
openchronicle startFull nuke including config:
openchronicle stop
rm -rf ~/.openchronicle
openchronicle start # recreates config.toml with defaultstail -F ~/.openchronicle/logs/*.logAll sinks in one terminal. When in doubt, run start --foreground and keep this tail open in another pane.